From 9f730b98ce084d71078745179fa04e0d0f8ba0f2 Mon Sep 17 00:00:00 2001 From: Andrey Novikov Date: Sun, 26 Nov 2017 23:29:16 +0300 Subject: [PATCH 1/2] Optimize page to hash convertation by not computing unneeded sections --- lib/tram/page.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/tram/page.rb b/lib/tram/page.rb index 637a329..de87c0b 100644 --- a/lib/tram/page.rb +++ b/lib/tram/page.rb @@ -28,10 +28,10 @@ def sections end def to_h(except: nil, only: nil, **) - obj = self.class.sections.values.map { |s| s.call(self) }.reduce({}, :merge) - obj = obj.reject { |k, _| Array(except).map(&:to_sym).include? k } if except - obj = obj.select { |k, _| Array(only).map(&:to_sym).include? k } if only - obj + sections = self.class.sections.dup + sections.select! { |k, _| Array(only).include? k } if only + sections.reject! { |k, _| Array(except).include? k } if except + sections.map { |_, section| section.call(self) }.reduce({}, :merge!) end private From adc3a72a2e4ab269409d16af159fbbbbdcffdafa Mon Sep 17 00:00:00 2001 From: Andrey Novikov Date: Wed, 22 Nov 2017 17:54:49 +0300 Subject: [PATCH 2/2] Allow to inherit one page from another To allow reuse of common sections and to allow to add or remove sections for specific cases. --- README.md | 18 +++++++++++++++++- lib/tram/page.rb | 12 +++++++++++- lib/tram/page/section.rb | 24 +++++++++++++++--------- spec/spec_helper.rb | 1 + spec/support/inherited_page.rb | 15 +++++++++++++++ spec/tram/inherited_page_spec.rb | 16 ++++++++++++++++ 6 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 spec/support/inherited_page.rb create mode 100644 spec/tram/inherited_page_spec.rb diff --git a/README.md b/README.md index c0a2b40..7fcd55a 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Or install it yourself as: ## Usage ```ruby -class class IndexPage < Tram::Page +class IndexPage < Tram::Page # See dry-initializer param :account option :readonly, optional: true @@ -52,6 +52,22 @@ IndexPage.new(Account.find(99)).to_h(except: :collection) IndexPage.new(Account.find(99)).to_h(only: :collection) ``` +Inheritance of page objects is supported: + +```ruby +class FancyIndexPage < IndexPage + inherit_section :title + section :fancy_collection + inherit_section :index_url, if: :readonly_on? + + def fancy_collection + collection.map(&:fancy) + end +end + +FancyIndexPage.new(Account.find(99)).to_h # => { :title => "…", fancy_collection: […] } +``` + ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. diff --git a/lib/tram/page.rb b/lib/tram/page.rb index de87c0b..a936358 100644 --- a/lib/tram/page.rb +++ b/lib/tram/page.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +require "dry-initializer" +require_relative "page/section" + class Tram::Page extend ::Dry::Initializer @@ -14,7 +17,14 @@ def section(name, options = {}) section = Section.new(name, options) sections[name] = section - define_method(name, §ion.block) if section.block + define_method(name, §ion.value) if section.value + end + + def inherit_section(name, option_overrides={}) + name = name.to_sym + parent_section = superclass.sections[name] + options = Tram::Page::Section.dry_initializer.attributes(parent_section) + section(name, options.merge(option_overrides)) end def url_helper(name) diff --git a/lib/tram/page/section.rb b/lib/tram/page/section.rb index ee136c4..7fac454 100644 --- a/lib/tram/page/section.rb +++ b/lib/tram/page/section.rb @@ -9,11 +9,10 @@ class Tram::Page class Section extend Dry::Initializer param :name, proc(&:to_sym) - option :method, proc(&:to_s), default: -> { name }, as: :method_name - option :value, proc(&:to_proc), optional: true, as: :block - option :if, proc(&:to_s), optional: true, as: :positive - option :unless, proc(&:to_s), optional: true, as: :negative - option :skip, true.method(:&), optional: true + option :method, proc(&:to_s), default: -> { name } + option :value, proc(&:to_proc), optional: true + option :if, proc(&:to_s), optional: true + option :unless, proc(&:to_s), optional: true # @param [Tram::Page] page # @return [Hash] a part of the section @@ -24,13 +23,20 @@ def call(page) private def skip_on?(page) - return true if skip - return true if positive && !page.public_send(positive) - return true if negative && page.public_send(negative) + return true if attributes[:if] && !page.__send__(attributes[:if]) + return true if attributes[:unless] && page.__send__(attributes[:unless]) end def value_at(page) - block ? page.instance_exec(&block) : page.public_send(method_name) + if attributes[:value] + page.instance_exec(&attributes[:value]) + else + page.public_send(attributes[:method]) + end + end + + def attributes + @attributes ||= self.class.dry_initializer.attributes(self) end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1ae54d4..072156c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,6 +5,7 @@ require "tram/page" require "support/blank_page" require "support/example_page" +require "support/inherited_page" RSpec.configure do |config| # Enable flags like --only-failures and --next-failure diff --git a/spec/support/inherited_page.rb b/spec/support/inherited_page.rb new file mode 100644 index 0000000..9f9b1dc --- /dev/null +++ b/spec/support/inherited_page.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class InheritedPage < ExamplePage + inherit_section :foo + inherit_section :bar, if: :no_bar + section :bam + + def bam + baz.upcase + end + + def no_bar + !bar + end +end diff --git a/spec/tram/inherited_page_spec.rb b/spec/tram/inherited_page_spec.rb new file mode 100644 index 0000000..db1eb32 --- /dev/null +++ b/spec/tram/inherited_page_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe InheritedPage do + subject { described_class.new("test") } + + it "returns data hash with new and without skipped fields" do + expect(subject.to_h).to eq(foo: "test", bam: "TEST") + end + + it "doesn't change behaviour of the parent class" do + expect(described_class.superclass.new("test").to_h).to \ + eq(bar: "test", foo: "test", baz: "test") + end +end