Make Dash greedier when creating getters

Dash, in its current form, was created to be very conservative in
creating the getters for its properties. It only creates them when the
accompanying setter has not already been created. This means that the
property translation capability that is layered on top of Dash to create
a Trash cannot have dependence between properties in an
order-independent way.

This change makes it so Dash now greedily creates a getter method for
each property. To ensure that we don't do this more than once for
a given Dash class, we track the getters we have previously created.
This keeps the number of warnings from Ruby down to the same number of
warnings that were emitted prior to this change.

Given that Dash users expect the getter to be set, this doesn't feel
like it should cause any backwards-compatibility issues.
This commit is contained in:
Michael Herold 2018-08-11 15:53:58 -05:00
parent b7209f6f58
commit 91a5153fa3
No known key found for this signature in database
GPG Key ID: 70391C233DE2F014
3 changed files with 35 additions and 12 deletions

View File

@ -1,16 +1,16 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2018-02-07 19:58:08 -0600 using RuboCop version 0.52.1.
# on 2018-08-11 15:53:09 -0500 using RuboCop version 0.52.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 9
# Offense count: 8
Metrics/AbcSize:
Max: 26
Max: 24
# Offense count: 57
# Offense count: 58
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
Max: 620
@ -42,14 +42,13 @@ Metrics/PerceivedComplexity:
Style/Documentation:
Enabled: false
# Offense count: 2
# Offense count: 1
# Cop supports --auto-correct.
Style/IfUnlessModifier:
Exclude:
- 'lib/hashie/extensions/dash/property_translation.rb'
- 'lib/hashie/extensions/strict_key_access.rb'
# Offense count: 256
# Offense count: 261
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:

View File

@ -42,11 +42,8 @@ module Hashie
defaults.delete property_name
end
unless instance_methods.map(&:to_s).include?("#{property_name}=")
define_method(property_name) { |&block| self.[](property_name, &block) }
property_assignment = "#{property_name}=".to_sym
define_method(property_assignment) { |value| self.[]=(property_name, value) }
end
define_getter_for(property_name)
define_setter_for(property_name)
@subclasses.each { |klass| klass.property(property_name, options) } if defined? @subclasses
@ -61,9 +58,11 @@ module Hashie
class << self
attr_reader :properties, :defaults
attr_reader :getters
attr_reader :required_properties
end
instance_variable_set('@properties', Set.new)
instance_variable_set('@getters', Set.new)
instance_variable_set('@defaults', {})
instance_variable_set('@required_properties', {})
@ -71,6 +70,7 @@ module Hashie
super
(@subclasses ||= Set.new) << klass
klass.instance_variable_set('@properties', properties.dup)
klass.instance_variable_set('@getters', getters.dup)
klass.instance_variable_set('@defaults', defaults.dup)
klass.instance_variable_set('@required_properties', required_properties.dup)
end
@ -87,6 +87,18 @@ module Hashie
required_properties.key? name
end
private_class_method def self.define_getter_for(property_name)
return if getters.include?(property_name)
define_method(property_name) { |&block| self.[](property_name, &block) }
getters << property_name
end
private_class_method def self.define_setter_for(property_name)
setter = :"#{property_name}="
return if instance_methods.include?(setter)
define_method(setter) { |value| self.[]=(property_name, value) }
end
# You may initialize a Dash with an attributes hash
# just like you would many other kinds of data objects.
def initialize(attributes = {}, &block)

View File

@ -312,5 +312,17 @@ describe Hashie::Trash do
expect(subject.to_h[:value]).to eq(nil)
expect(subject.copy_of_value).to eq(0)
end
it 'is not order-dependent in definition' do
simple = Class.new(Hashie::Trash) do
property :copy_of_id, from: :id
property :id
end
subject = simple.new(id: 1)
expect(subject.id).to eq(1)
expect(subject.copy_of_id).to eq(1)
end
end
end