Skip to content

Commit

Permalink
Refactor props and fix OptionalProp.new(false)
Browse files Browse the repository at this point in the history
  • Loading branch information
skryukov committed Oct 28, 2024
1 parent f12cc88 commit b8f84c3
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 103 deletions.
18 changes: 4 additions & 14 deletions lib/inertia_rails/base_prop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,12 @@ def initialize(value = nil, &block)
@block = block
end

def call
to_proc.call
def call(controller)
value.respond_to?(:call) ? controller.instance_exec(&value) : value
end

private

def to_proc
# This is called by controller.instance_exec, which changes self to the
# controller instance. That makes the instance variables unavailable to the
# proc via closure. Copying the instance variables to local variables before
# the proc is returned keeps them in scope for the returned proc.
value = @value
return value if value.respond_to?(:call)
return Proc.new { value } if value

@block
def value
@value.nil? ? @block : @value
end
end
end
2 changes: 2 additions & 0 deletions lib/inertia_rails/middleware.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

module InertiaRails
class Middleware
def initialize(app)
Expand Down
22 changes: 14 additions & 8 deletions lib/inertia_rails/renderer.rb
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"
Expand Down Expand Up @@ -84,12 +86,16 @@ def computed_props

drop_partial_except_keys(_props) if rendering_partial_component?

deep_transform_values(
_props,
lambda do |prop|
prop.respond_to?(:call) ? controller.instance_exec(&prop) : prop
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
Expand All @@ -111,10 +117,10 @@ def page
default_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)
Expand Down
3 changes: 3 additions & 0 deletions spec/dummy/app/controllers/application_controller.rb
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
19 changes: 1 addition & 18 deletions spec/inertia/always_prop_spec.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,3 @@
RSpec.describe InertiaRails::AlwaysProp do
describe '#call' do
subject(:call) { prop.call }
let(:prop) { described_class.new('value') }

it { is_expected.to eq('value') }

context 'with a callable value' do
let(:prop) { described_class.new(-> { 'callable' }) }

it { is_expected.to eq('callable') }
end

context 'with a block' do
let(:prop) { described_class.new { 'block' } }

it { is_expected.to eq('block') }
end
end
it_behaves_like 'callable prop'
end
3 changes: 3 additions & 0 deletions spec/inertia/base_prop_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
RSpec.describe InertiaRails::BaseProp do
it_behaves_like 'callable prop'
end
37 changes: 14 additions & 23 deletions spec/inertia/defer_prop_spec.rb
Original file line number Diff line number Diff line change
@@ -1,51 +1,42 @@
RSpec.describe InertiaRails::DeferProp do
describe '#call' do
subject(:call) { prop.call }
let(:prop) { described_class.new('value') }
let(:prop) { described_class.new('value') }

it { is_expected.to eq('value') }
it_behaves_like 'callable prop'

describe '#group' do
subject(:group) { prop.group }

it 'returns the default group' do
expect(prop.group).to eq('default')
expect(group).to eq('default')
end

context "with group" do
context "with a custom group" do
let(:prop) { described_class.new('value', group: 'custom') }

it 'returns the group' do
expect(prop.group).to eq('custom')
expect(group).to eq('custom')
end
end

context 'with a callable value' do
let(:prop) { described_class.new(-> { 'callable' }) }

it { is_expected.to eq('callable') }

context "with group" do
context 'with a callable value' do
let(:prop) { described_class.new(-> { 'callable' }, group: 'custom') }

it 'returns the group' do
expect(prop.group).to eq('custom')
expect(group).to eq('custom')
end
end
end

context 'with a block' do
let(:prop) { described_class.new { 'block' } }

it { is_expected.to eq('block') }

context "with group" do
context 'with a block' do
let(:prop) { described_class.new(group: 'custom') { 'block' } }

it 'returns the group' do
expect(prop.group).to eq('custom')
end
end
end
end

it 'returns the merge flag' do
describe '#merge' do
it 'updates the merge value' do
expect(prop.merge?).to be_falsey
prop.merge

Expand Down
25 changes: 6 additions & 19 deletions spec/inertia/merge_prop_spec.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
RSpec.describe InertiaRails::MergeProp do
describe '#call' do
subject(:call) { prop.call }
let(:prop) { described_class.new('value') }
let(:prop) { described_class.new('value') }

it { is_expected.to eq('value') }
describe '#merge?' do
subject { prop.merge? }

context 'with a callable value' do
let(:prop) { described_class.new(-> { 'callable' }) }

it { is_expected.to eq('callable') }
end

context 'with a block' do
let(:prop) { described_class.new { 'block' } }

it { is_expected.to eq('block') }
end

it 'returns the merge flag' do
expect(prop.merge?).to eq(true)
end
it { is_expected.to be(true) }
end

it_behaves_like 'callable prop'
end
20 changes: 1 addition & 19 deletions spec/inertia/optional_prop_spec.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
RSpec.describe InertiaRails::OptionalProp do
describe '#call' do
context 'with a value' do
it 'returns the value' do
expect(InertiaRails::OptionalProp.new('thing').call).to eq('thing')
end
end

context 'with a callable value' do
it 'returns the result of the callable value' do
expect(InertiaRails::OptionalProp.new(->{ 'thing' }).call).to eq('thing')
end
end

context 'with a block' do
it 'returns the result of the block' do
expect(InertiaRails::OptionalProp.new {'thing'}.call).to eq('thing')
end
end
end
it_behaves_like 'callable prop'
end
3 changes: 1 addition & 2 deletions spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
# Require the spec/support directory and its subdirectories.
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
Dir[Pathname.new(__dir__).join('support', '**', '*.rb')].each { |f| require f }

require_relative './support/helper_module'
# Add additional requires below this line. Rails is not loaded until this point!
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
Expand Down
45 changes: 45 additions & 0 deletions spec/support/shared_examples.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
RSpec.shared_examples 'callable prop' do
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 a callable value' do
let(:prop) { described_class.new(-> { 'callable' }) }

it { is_expected.to eq('callable') }

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 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

context 'with a block' do
let(:prop) { described_class.new { 'block' } }

it { is_expected.to eq('block') }

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

0 comments on commit b8f84c3

Please sign in to comment.