diff --git a/lib/jekyll/drops/drop.rb b/lib/jekyll/drops/drop.rb index 2d31989e..87eed39b 100644 --- a/lib/jekyll/drops/drop.rb +++ b/lib/jekyll/drops/drop.rb @@ -6,6 +6,8 @@ module Jekyll include Enumerable NON_CONTENT_METHODS = [:fallback_data, :collapse_document].freeze + NON_CONTENT_METHOD_NAMES = NON_CONTENT_METHODS.map(&:to_s).freeze + private_constant :NON_CONTENT_METHOD_NAMES # A private stash to avoid repeatedly generating the setter method name string for # a call to `Drops::Drop#[]=`. @@ -88,6 +90,17 @@ module Jekyll def data_delegator(key) define_method(key.to_sym) { @obj.data[key] } end + + # Array of stringified instance methods that do not end with the assignment operator. + # + # (.instance_methods always generates a new Array object so it can be mutated) + # + # Returns array of strings. + def getter_method_names + @getter_method_names ||= instance_methods.map!(&:to_s).tap do |list| + list.reject! { |item| item.end_with?("=") } + end + end end # Create a new Drop @@ -152,9 +165,10 @@ module Jekyll # # Returns an Array of strings which represent method-specific keys. def content_methods - @content_methods ||= ( - self.class.instance_methods - Jekyll::Drops::Drop.instance_methods - NON_CONTENT_METHODS - ).map!(&:to_s).tap { |result| result.reject! { |method| method.end_with?("=") } } + @content_methods ||= \ + self.class.getter_method_names \ + - Jekyll::Drops::Drop.getter_method_names \ + - NON_CONTENT_METHOD_NAMES end # Check if key exists in Drop diff --git a/test/test_drop.rb b/test/test_drop.rb index aa9387db..43016663 100644 --- a/test/test_drop.rb +++ b/test/test_drop.rb @@ -5,6 +5,8 @@ require "helper" class DropFixture < Jekyll::Drops::Drop mutable true + attr_accessor :lipsum + def foo "bar" end @@ -40,6 +42,39 @@ class TestDrop < JekyllUnitTest assert_equal "bar", @drop.invoke_drop("foo") end + should "return array of strings for .getter_methods" do + assert(@drop.class.getter_method_names.all? { |entry| entry.is_a?(String) }) + end + + should "return array of only getter method name strings for .getter_methods" do + [:lipsum, :lipsum=].each { |id| assert_includes(@drop.class.instance_methods, id) } + + assert_includes @drop.class.getter_method_names, "lipsum" + refute_includes @drop.class.getter_method_names, "lipsum=" + end + + should "not munge results for another Jekyll::Drops::Drop subclass" do + fixture_ids = [:lipsum, :lipsum=, :foo] + fixture_getter_names = %w(lipsum foo) + fixture_ids.each { |id| assert_includes(@drop.class.instance_methods, id) } + + fixture_getter_names.each do |name| + assert_includes @drop.class.getter_method_names, name + refute_includes @document_drop.class.getter_method_names, name + end + end + + should "return only getter method names for #content_methods" do + drop_base_class_method_names = Jekyll::Drops::Drop.instance_methods.map(&:to_s) + sample_method_names = ["lipsum=", "fallback_data", "collapse_document"] + + (sample_method_names + drop_base_class_method_names).each do |entry| + refute_includes @drop.content_methods, entry + end + + assert_equal %w(foo lipsum), @drop.content_methods.sort + end + context "mutations" do should "return mutations for #[]" do @drop["foo"] = "baz"