-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for always
and except
#152
Changes from all commits
68410ac
d98e817
3302b25
6ea5879
6b99131
f35d898
13ab57f
35ac7c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# frozen_string_literal: true | ||
|
||
module InertiaRails | ||
class AlwaysProp < BaseProp | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# frozen_string_literal: true | ||
|
||
module InertiaRails | ||
# Base class for all props. | ||
class BaseProp | ||
def initialize(&block) | ||
@block = block | ||
end | ||
|
||
def call(controller) | ||
controller.instance_exec(&@block) | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,26 @@ | ||
# Needed for `thread_mattr_accessor` | ||
require 'active_support/core_ext/module/attribute_accessors_per_thread' | ||
require 'inertia_rails/lazy' | ||
require 'inertia_rails/base_prop' | ||
require 'inertia_rails/always_prop' | ||
require 'inertia_rails/lazy_prop' | ||
require 'inertia_rails/configuration' | ||
|
||
module InertiaRails | ||
CONFIGURATION = Configuration.default | ||
class << self | ||
CONFIGURATION = Configuration.default | ||
|
||
def self.configure | ||
yield(CONFIGURATION) | ||
end | ||
def configure | ||
yield(CONFIGURATION) | ||
end | ||
|
||
def self.configuration | ||
CONFIGURATION | ||
end | ||
def configuration | ||
CONFIGURATION | ||
end | ||
|
||
def lazy(value = nil, &block) | ||
LazyProp.new(value, &block) | ||
end | ||
|
||
def self.lazy(value = nil, &block) | ||
InertiaRails::Lazy.new(value, &block) | ||
def always(&block) | ||
AlwaysProp.new(&block) | ||
end | ||
end | ||
end |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# frozen_string_literal: true | ||
|
||
module InertiaRails | ||
class LazyProp < BaseProp | ||
def initialize(value = nil, &block) | ||
raise ArgumentError, 'You must provide either a value or a block, not both' if value && block | ||
|
||
@value = value | ||
@block = block | ||
end | ||
|
||
def call(controller) | ||
value.respond_to?(:call) ? controller.instance_exec(&value) : value | ||
end | ||
|
||
def value | ||
@value.nil? ? @block : @value | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'net/http' | ||
require 'json' | ||
require_relative "inertia_rails" | ||
|
@@ -64,24 +66,34 @@ def shared_data | |
# Functionally, this permits using either string or symbol keys in the controller. Since the results | ||
# is cast to json, we should treat string/symbol keys as identical. | ||
def merge_props(shared_data, props) | ||
shared_data.deep_symbolize_keys.send(@deep_merge ? :deep_merge : :merge, props.deep_symbolize_keys) | ||
if @deep_merge | ||
shared_data.deep_symbolize_keys.deep_merge!(props.deep_symbolize_keys) | ||
else | ||
shared_data.symbolize_keys.merge(props.symbolize_keys) | ||
end | ||
end | ||
|
||
def computed_props | ||
_props = merge_props(shared_data, props).select do |key, prop| | ||
if rendering_partial_component? | ||
key.in? partial_keys | ||
partial_keys.none? || key.in?(partial_keys) || prop.is_a?(AlwaysProp) | ||
else | ||
!prop.is_a?(InertiaRails::Lazy) | ||
!prop.is_a?(LazyProp) | ||
end | ||
end | ||
|
||
deep_transform_values( | ||
_props, | ||
lambda do |prop| | ||
prop.respond_to?(:call) ? controller.instance_exec(&prop) : prop | ||
drop_partial_except_keys(_props) if rendering_partial_component? | ||
bknoles marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
deep_transform_values _props do |prop| | ||
case prop | ||
when BaseProp | ||
prop.call(controller) | ||
when Proc | ||
controller.instance_exec(&prop) | ||
else | ||
prop | ||
end | ||
) | ||
end | ||
end | ||
|
||
def page | ||
|
@@ -93,18 +105,32 @@ def page | |
} | ||
end | ||
|
||
def deep_transform_values(hash, proc) | ||
return proc.call(hash) unless hash.is_a? Hash | ||
def deep_transform_values(hash, &block) | ||
return block.call(hash) unless hash.is_a? Hash | ||
|
||
hash.transform_values {|value| deep_transform_values(value, proc)} | ||
hash.transform_values {|value| deep_transform_values(value, &block)} | ||
end | ||
|
||
def drop_partial_except_keys(hash) | ||
partial_except_keys.each do |key| | ||
parts = key.to_s.split('.').map(&:to_sym) | ||
*initial_keys, last_key = parts | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this supports dot notation, yea? so like do the other adapters support that? I don't see it documented anywhere. either way, if we support it for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
yup, Laravel adapter supports that
Laravel adapter does not 😄 To be honest the whole There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually they reverted back dot notation for
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh nice find! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, i dug into this a bit. TL;DR: I don't think those issues will affect our implementation. Best I can tell (caveat: using my brain's PHP interpreter) is that the original implementation of Laravel's InertiaRails 1) has explicit patterns for deep merging shared data and 2) doesn't support dot notation in shared data anyway, so we should be totally fine. I don't see a reason why we couldn't support dot notation for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, let's try adding support for ’only’ in a separate PR 👍 |
||
current = initial_keys.any? ? hash.dig(*initial_keys) : hash | ||
|
||
current.delete(last_key) if current.is_a?(Hash) && !current[last_key].is_a?(AlwaysProp) | ||
end | ||
end | ||
|
||
def partial_keys | ||
(@request.headers['X-Inertia-Partial-Data'] || '').split(',').compact.map(&:to_sym) | ||
end | ||
|
||
def partial_except_keys | ||
(@request.headers['X-Inertia-Partial-Except'] || '').split(',').filter_map(&:to_sym) | ||
end | ||
|
||
def rendering_partial_component? | ||
@request.inertia_partial? && @request.headers['X-Inertia-Partial-Component'] == component | ||
@request.headers['X-Inertia-Partial-Component'] == component | ||
end | ||
|
||
def resolve_component(component) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
class ApplicationController < ActionController::Base | ||
def controller_method | ||
'controller_method value' | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
RSpec.describe InertiaRails::AlwaysProp do | ||
it_behaves_like 'base prop' | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
RSpec.describe InertiaRails::BaseProp do | ||
it_behaves_like 'base prop' | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
RSpec.describe InertiaRails::LazyProp do | ||
it_behaves_like 'base prop' | ||
|
||
describe '#call' do | ||
subject(:call) { prop.call(controller) } | ||
let(:prop) { described_class.new('value') } | ||
let(:controller) { ApplicationController.new } | ||
|
||
it { is_expected.to eq('value') } | ||
|
||
context 'with false as value' do | ||
let(:prop) { described_class.new(false) } | ||
|
||
it { is_expected.to eq(false) } | ||
end | ||
|
||
context 'with nil as value' do | ||
let(:prop) { described_class.new(nil) } | ||
|
||
it { is_expected.to eq(nil) } | ||
end | ||
|
||
context 'with a callable value' do | ||
let(:prop) { described_class.new(-> { 'callable' }) } | ||
|
||
it { is_expected.to eq('callable') } | ||
|
||
context 'with dependency on the context of a controller' do | ||
let(:prop) { described_class.new(-> { controller_method }) } | ||
|
||
it { is_expected.to eq('controller_method value') } | ||
end | ||
end | ||
end | ||
end |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this. Half-baked thought: I wonder if we could move more rendering logic into the
Prop
classes. Thecomputed_props
method is doing more and more things in a sort of procedural style. Maybe it could iterate over the props one time and each instance would know what to do with itself.(Not suggesting changes, more just thinking out loud)