cushion_defaults 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a81419a81ff0cdcd46f6c56967342aa8c0663853
4
+ data.tar.gz: 32731179906c9bbe94c7e56a1e5716409214c548
5
+ SHA512:
6
+ metadata.gz: 5f2c6ef61d48aa83e0ff9723c68e807a159926c5a74e10109b1f0354a9d4b877f7525b6f518add68e7668d0eb01f8d95c9e480fb434d01634b310defab80e180
7
+ data.tar.gz: 364a9f1df425222db45df3ee27c703ecb8401a4a075c53bb8e648ec8526fc7452f7ae8955c5437a87250cb04e1680775b753803d5388dacb4688c9996e3b64bd
@@ -0,0 +1,189 @@
1
+ module CushionDefaults
2
+ # A series of class methods to be plopped into any class that includes CushionDefaults.
3
+ module ClassMethods
4
+
5
+ # Getter-method for the +defaults+ +DefaultsHash+.
6
+ attr_reader :defaults
7
+
8
+ # Either set up or wipe @defaults. Should not usually be called directly.
9
+ def initialize_defaults_hash
10
+
11
+ if @defaults
12
+ # We need to maintain the identity of the hash, as child classes may have stored a reference to it
13
+ @defaults.delete_if { true }
14
+ else
15
+ @defaults = DefaultsHash.new(self)
16
+ end
17
+ end
18
+
19
+ # Wipe @defaults and replace it with the keys/vals of +replacement_hash+.
20
+ #
21
+ # If you only want to add one or more defaults, then write instead self.defaults += {new_key: val}.
22
+ #
23
+ # Note that all keys are coerced into +Symbols+.
24
+ # +replacement_hash+ :: a hash (of any length) whose keys/values are to be replace those in +defaults+.
25
+ def defaults=(replacement_hash)
26
+ # Need to copy over keys/vals to ensure @defaults remains a DefaultsHash and retains identity
27
+
28
+ @defaults.replace(replacement_hash)
29
+ @defaults.keys.each do |key|
30
+ unless key.is_a? Symbol
31
+ @defaults[key.to_sym] = @defaults[key].delete!
32
+ end
33
+ end
34
+ end
35
+
36
+ # Convenience method equivalent to +@defaults[key] = val+
37
+ # +key+ :: Key for new default. Is coerced into a +Symbol+.
38
+ # +val+ :: Default value for +key+.
39
+ def set_default(key, val)
40
+ @defaults[key.to_sym] = val
41
+ end
42
+
43
+ # Load in the defaults for this class from a yaml file.
44
+ # If +source_path+ is specified, yaml file is loaded from there.
45
+ # Otherwise, *CushionDefaults::YAML_PATH* is evaluated for the current class.
46
+ # By default, the yaml file for +Klass+ is expected to be at +config/klass.yaml+.
47
+ # +source_path+ :: File path to the yaml configuration file for this class
48
+ def defaults_from_yaml(source_path = nil)
49
+ if source_path
50
+ yaml_path = "#{CushionDefaults::configuration.yaml_source_full_path}#{source_path}.yaml"
51
+ else
52
+ yaml_path = CushionDefaults.conf.yaml_file_for(self)
53
+ end
54
+
55
+ yaml = YAML::load(File.open(yaml_path)) rescue {}
56
+
57
+ if yaml.empty? && CushionDefaults::configuration.whiny_yaml
58
+ warn "No YAML configuration for class #{self} found at #{yaml_path}"
59
+ end
60
+
61
+ initialize_defaults_hash
62
+ # If automatic readers and writers are enabled, this will set them up as a consequence.
63
+ yaml.each do |key, val|
64
+ @defaults[key.to_sym] = val
65
+ end
66
+ end
67
+
68
+ # Sets up a conditional getter method for each :sym in +syms+.
69
+ #
70
+ # Each getter method checks if its instance variable (:sym) is defined. If it is, it returns that. If not, it
71
+ # returns the default value.
72
+ #
73
+ # The getters are named according to the same format as +attr_reader+.
74
+ # +syms+ :: One or more +Symbol+s representing those instance variables that should have +conditional_getters+
75
+ def cushion_reader(*syms)
76
+ syms.each do |sym|
77
+ sym = sym.to_sym
78
+ sym_str = sym.to_s
79
+ if self_or_parent_instance_method?(sym)
80
+ warn "#{self} or a parent class already has what looks like a getter method for #{sym_str}"
81
+ end
82
+ define_method(sym) do
83
+ instance_variable_string = "@#{sym_str}"
84
+ if defaults.not_pushy?(sym) && instance_variable_defined?(instance_variable_string)
85
+ instance_variable_get(instance_variable_string)
86
+ else
87
+ defaults[sym]
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ def cushion_writer(*syms)
94
+ syms.each do |sym|
95
+ method_name = "#{sym}="
96
+ if self_or_parent_instance_method?(method_name)
97
+ warn "#{self} or a parent class already has what looks like a setter method for #{sym}"
98
+ end
99
+
100
+ instance_variable_string = "@#{sym}"
101
+
102
+ define_method(method_name) do |y|
103
+ if CushionDefaults.nilish? y
104
+ if CushionDefaults.conf.whiny_ignores
105
+ warn "You are attempting to set a nilish value for #{sym}. This will not be recorded, and any value set will be deleted."
106
+ end
107
+ remove_instance_variable(instance_variable_string) if instance_variable_defined?(instance_variable_string)
108
+ else
109
+ if defaults.pushy?(sym)
110
+ warn "You are setting a value for #{sym}, but this is a pushy default and this value will not be returned by any cushion_readers."
111
+ end
112
+ instance_variable_set(instance_variable_string, y)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ def remove_reader(sym)
119
+ undef_method(sym) if self_has_method?(sym)
120
+ end
121
+
122
+ def remove_writer(sym)
123
+ write_sym = "#{sym}=".to_sym
124
+ undef_method(write_sym) if self_has_method?(write_sym)
125
+ end
126
+
127
+ # Sets up both +conditional_getters+ and normal +attr_writer+ for +syms+.
128
+ # +syms+ :: One or more symbols representing those instance variables that should have +conditional_getters+ and normal +attr_writers+.
129
+ def cushion(*syms)
130
+ cushion_reader(*syms)
131
+
132
+ cushion_writer(*syms)
133
+ end
134
+
135
+ # Defines +conditional_getters+ for all of this class' +defaults+.
136
+ #
137
+ # Only defines +conditional_getters+ for defaults for this class. All other getters are assumed to have been defined
138
+ # further up the class tree.
139
+ #
140
+ # Thus, if class +A+ defines the default +var1+, and class +B+ defines the default +var2+, calling this method
141
+ # within class +B+ will only generate a getter for +var2+.
142
+ def cushion_readers_for_defaults
143
+ cushion_reader *defaults.keys
144
+ end
145
+
146
+ # Defines +conditional_getters+ and +attr_writers+ for all of this class' +defaults+.
147
+ #
148
+ # Only defines +conditional_getters+ for this class defaults. All other getters are assumed to have been defined
149
+ # further up the class tree.
150
+ #
151
+ # Thus, if class +A+ defines the default +var1+, and class +B+ defines the default +var2+, calling this method
152
+ # within class +B+ will only generate a getter for +var2+.
153
+ #
154
+ # See also:
155
+ # - #cushion
156
+ # - #cushion_readers_for_defaults
157
+ def cushion_defaults
158
+ cushion *defaults.keys
159
+ end
160
+
161
+ def make_pushy(*syms)
162
+ syms.each { |sym| @defaults.pushy!(sym) }
163
+ end
164
+
165
+ def make_polite(*syms)
166
+ syms.each { |sym| @defaults.not_pushy!(sym) }
167
+ end
168
+
169
+ # Ensure that if class +Klass+ includes +CushionDefaults+, then any class that subclasses +Klass+ will include it as
170
+ # well.
171
+ #
172
+ # Called automatically whenever any class that includes +CushionDefaults+ is inherited.
173
+ def inherited(inheritor)
174
+ inheritor.send :include, CushionDefaults
175
+ end
176
+
177
+ protected
178
+
179
+ # Check whether this class or any parent class includes the instance method denoted by +sym+
180
+ # +sym+ :: Symbol representing the method in question
181
+ def self_or_parent_instance_method?(sym)
182
+ instance_methods(true).include?(sym.to_sym)
183
+ end
184
+
185
+ def self_has_method?(sym)
186
+ instance_methods(false).include?(sym.to_sym)
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,56 @@
1
+ # Effectively a singleton class, +Configuration+ keeps track of various configuration options for +CushionDefaults+.
2
+ class Configuration # :nodoc:
3
+ # adapted from http://brandonhilkert.com/blog/ruby-gem-configuration-patterns/
4
+
5
+ attr_accessor :update_readers, :update_writers, :auto_load_from_yaml, :yaml_source_folder, :yaml_source_full_path, :whiny_yaml, :whiny_ignores, :cushion_child_defaults_in_parent, :ignore_attempts_to_set_nil, :blank_str_is_nil
6
+
7
+ # Initializes with +#defaults+
8
+ def initialize
9
+ defaults!
10
+ end
11
+
12
+ # Returns or computes the folder where class-specific yaml files are expected to reside.
13
+ def yaml_source_full_path
14
+ @yaml_source_full_path || CushionDefaults::CALLING_PATH + yaml_source_folder
15
+ end
16
+
17
+ # Update configuration options with those values contained within +loaded_config+.
18
+ #
19
+ # +loaded_config+ :: hash from which options will be derived
20
+ def from_hash(loaded_config)
21
+ loaded_config.each do |key, val|
22
+ instance_variable_set(key.to_sym, val) if instance_variable_defined? key.to_sym
23
+ end
24
+ end
25
+
26
+ # Defines default configuration settings
27
+ def defaults!
28
+ self.update_readers = false
29
+ self.update_writers = false
30
+ self.auto_load_from_yaml = true
31
+ self.yaml_source_folder = 'config/cushion_defaults/'
32
+ self.yaml_source_full_path = nil
33
+ self.whiny_yaml = false
34
+ self.whiny_ignores = false
35
+ self.ignore_attempts_to_set_nil = true
36
+ self.blank_str_is_nil = true
37
+ end
38
+
39
+ def test_settings!
40
+ defaults!
41
+ self.whiny_yaml = true
42
+ self.whiny_ignores = true
43
+ end
44
+
45
+ def underscore(s)
46
+ s.gsub(/::/, '/').
47
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
48
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
49
+ tr("-", "_").
50
+ downcase
51
+ end
52
+
53
+ def yaml_file_for(klass)
54
+ "#{CushionDefaults::configuration.yaml_source_full_path}#{underscore(klass.to_s)+'.yaml'}"
55
+ end
56
+ end
@@ -0,0 +1,165 @@
1
+ module CushionDefaults
2
+ # Slight expansion of +Hash+.
3
+ #
4
+ # Records a link to +owner+ and will traverse up the chain of owners looking for a default value for +x+ if no default
5
+ # value for +x+ is specified.
6
+ class DefaultsHash < Hash
7
+ # +default_proc+ does most of the work.
8
+
9
+ # Must be initialized with an +owner+ class.
10
+
11
+ attr_reader :pushy_defaults, :polite_defaults
12
+
13
+ # +owner+ :: Class for which this +DefaultsHash+ contains defaults.
14
+ def initialize(owner)
15
+ self.default_proc = proc { |_hash, key| super_defaults[key] }
16
+ # look in the superclass' +defaults+ hash, if a key is not found in this class' +defaults+ hash
17
+ @owner = owner
18
+ @pushy_defaults = Set.new
19
+ @polite_defaults = Set.new
20
+ end
21
+
22
+ # Allow addition of hashes. Works as expected.
23
+ #
24
+ # Note that this also enables +=.
25
+ #
26
+ # If +key+ is in +self+ and +y+, then the value of +y+ will replace that in +self+ in the resulting +Hash+.
27
+ # +y+ :: Hash (of any length) whose key/values will be added to this +DefaultsHash+.
28
+ def +(y)
29
+ y.each {|key, val| self[key] = val}
30
+ self
31
+ end
32
+
33
+ def add_methods_as_needed(key)
34
+ @owner.cushion_reader key.to_sym if CushionDefaults.conf.update_readers
35
+ @owner.cushion_writer key.to_sym if CushionDefaults.conf.update_writers
36
+ end
37
+
38
+ def remove_methods_as_needed(key)
39
+ @owner.remove_reader key.to_sym if CushionDefaults.conf.update_readers
40
+ @owner.remove_writer key.to_sym if CushionDefaults.conf.update_writers
41
+ end
42
+
43
+ # Custom key/value set method. Prevents writing a default when a parent has it marked as pushy (and it is not
44
+ # otherwise marked as polite), and it also tells @owner to add methods as needed (if writers or readers are to be
45
+ # automatically added).
46
+ def []=(key,val)
47
+ key = key.to_sym
48
+ if !@polite_defaults.include?(key) && pushy_in_parent?(key)
49
+ raise ArgumentError, 'You cannot set a default value marked as pushy in a parent class without first marking it as polite.'
50
+ end
51
+ unless has_ish_key?(key)
52
+ add_methods_as_needed(key)
53
+ end
54
+ super(key, val)
55
+ end
56
+
57
+ # Custom delete method. We need to check whether or not we should delete the methods associated with the key, and we
58
+ # need to remove the key from @pushy_defaults and @polite_defaults if it exists.
59
+ def delete(key)
60
+ key = key.to_sym
61
+ remove_methods_as_needed(key)
62
+ @pushy_defaults.delete(key)
63
+ @polite_defaults.delete(key)
64
+ super(key)
65
+ end
66
+
67
+ # Custom clear method. We need to check whether or not we should delete the methods associated with the keys, and we
68
+ # need to wipe @pushy_defaults and @polite_defaults.
69
+ def clear
70
+ keys.each do |key|
71
+ remove_methods_as_needed(key.to_sym)
72
+ end
73
+ @pushy_defaults.clear
74
+ @polite_defaults.clear
75
+ super
76
+ end
77
+
78
+ # Custom clear method. We need to check whether or not we should delete the methods associated with the key.
79
+
80
+ # Determine if this +DefaultsHash+ "ish" has a key. In other words, whether it or any Hashes up the chain of
81
+ # +super_defaults+ has the key +key+.
82
+ #
83
+ # See also:
84
+ # - #ish_keys
85
+ def has_ish_key?(key)
86
+ # Obviously, this method gives much better performance than calling +ish_keys.include?(key)+.
87
+ if has_key?(key)
88
+ true
89
+ elsif !super_defaults.empty?
90
+ # super_defaults could theoretically be either a DefaultsHash or a regular Hash
91
+ if super_defaults.respond_to? :has_ish_key?
92
+ super_defaults.has_ish_key?(key)
93
+ else
94
+ super_defaults.has_key?(key)
95
+ end
96
+ else
97
+ false
98
+ end
99
+ end
100
+
101
+ # Returns the keys of this class' +defaults+ as well as those of parent classes (if extant).
102
+ #
103
+ # See also:
104
+ # - #has_ish_key?
105
+ def ish_keys
106
+ if super_defaults
107
+ # super_defaults could be either a DefaultsHash or a regular Hash
108
+ (keys + (super_defaults.respond_to?(:ish_keys) ? super_defaults.ish_keys : super_defaults.keys)).uniq
109
+ else
110
+ keys
111
+ end
112
+ end
113
+
114
+ def pushy!(sym)
115
+ @pushy_defaults.add(sym)
116
+ @polite_defaults.delete(sym)
117
+ end
118
+
119
+ def not_pushy!(sym)
120
+ @pushy_defaults.delete(sym)
121
+ @polite_defaults.add(sym)
122
+ end
123
+
124
+ def pushy?(sym)
125
+ if @polite_defaults.include?(sym)
126
+ # white list has priority
127
+ false
128
+ elsif @pushy_defaults.include?(sym)
129
+ true
130
+ else
131
+ pushy_in_parent?(sym)
132
+ end
133
+ end
134
+
135
+ def pushy_in_parent?(sym)
136
+ if super_defaults.respond_to? :pushy?
137
+ super_defaults.pushy?(sym)
138
+ else
139
+ false
140
+ end
141
+ end
142
+
143
+ def not_pushy?(sym)
144
+ !pushy?(sym)
145
+ end
146
+
147
+
148
+ def where_is_that_default_again(sym)
149
+ if has_key? sym
150
+ @owner
151
+ elsif super_defaults.respond_to? :where_is_that_default_again
152
+ super_defaults.where_is_that_default_again sym
153
+ else
154
+ nil
155
+ end
156
+ end
157
+
158
+ protected
159
+
160
+ # Return (unless cached) a reference to the superclass' +defaults+ hash.
161
+ def super_defaults
162
+ @super_defaults ||= @owner.superclass.respond_to?(:defaults) ? @owner.superclass.defaults : {}
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,120 @@
1
+ require 'YAML' # :nodoc:
2
+ require 'set' # :nodoc:
3
+ require 'cushion_defaults/configuration'
4
+ require 'cushion_defaults/class_methods'
5
+ require 'cushion_defaults/defaults_hash'
6
+
7
+ # Base module. Should be included in any class that needs the functionality offered by +CushionDefaults+.
8
+ #
9
+ # When included in a superclass +Klass+, it automatically includes itself in all subclassses that subsequently extend
10
+ # +Klass+.
11
+ module CushionDefaults
12
+
13
+ VERSION = '0.0.0'
14
+
15
+ # CONFIG
16
+
17
+ # Location CushionDefaults looks for (optional) config file
18
+ CONFIG_LOCATION = 'config/cushion_defaults.yaml'
19
+
20
+ CALLING_PATH = File.expand_path(File.dirname($0)) + '/'
21
+
22
+ # If set to true, will automatically look at +YAML_PATH+ for each class that includes +CushionDefaults+ to try to
23
+ # load defaults from yaml file located at the result of +YAML_PROC+. By default, this would be 'config/klass.yaml'.
24
+
25
+ # Relative folder path to yaml file used both automatically if +AUTO_LOAD_FROM_YAML+ and with unparam'd manual calls
26
+ # to +#defaults_from_yaml+.
27
+
28
+ # If true, will complain (i.e., throw a warning) if a yaml file cannot be found for a class, whether called because of
29
+ # AUTO_LOAD_FROM_YAML or via a manual call to +#defaults_from_yaml+.
30
+
31
+ # Create or return a cached (singleton) +Configuration+ object.
32
+ def self.configuration
33
+ @configuration ||= Configuration.new
34
+ end
35
+
36
+ def self.conf
37
+ self.configuration
38
+ end
39
+
40
+ def self.nilish?(y)
41
+ if conf.ignore_attempts_to_set_nil
42
+ y.nil? || (conf.blank_str_is_nil && y.eql?(''))
43
+ else
44
+ false
45
+ end
46
+ end
47
+
48
+ # Yield the configuration object to a block.
49
+ #
50
+ # The following configuration methods are available with the returned object:
51
+ # - #maintain_getters (boolean) :: If true, cushion_getters will be added/removed automatically as defaults are added/removed.
52
+ # - #maintain_writers (boolean) :: If true, cushion_setters will be added/removed automatically as defaults are added/removed.
53
+ # - #auto_load_from_yaml (boolean) :: Specifies whether we should attempt to automatically load defaults from class-specific yaml files. Def: true.
54
+ # - #yaml_source_folder (string) :: Specifies the folder that contains class-specific yaml files. Def: 'config/cushion_defaults/'.
55
+ # - #yaml_source_full_path (string) :: Specifies the full path for class-specific yaml files. Def: +nil+.
56
+ # - #whiny_yaml (boolean) :: If true, a warning will be issued if a class-specific yaml file cannot be found. Def: false.
57
+ # - #whiny_ignores (boolean) :: If true, a warning will be issued when a variable is not set (or is undefined) due to being nilish. Def: false.
58
+ # - #cushion_child_defaults_in_parent (boolean) :: If true, then if SubKlass < Klass and getters/setters are added for a default specified in Subklass, then a getter that returns nil will be added to Klass as well. Def: false.
59
+ # - #ignore_attempts_to_set_nil (boolean) :: If true, then if a cushion_writer has been added for :x, then calling var.x = nil will instead remove_instance_variable(x) on var, effectively making it so that var.x will return the default value for x. Def: true.
60
+ # - #blank_str_is_nil (boolean) :: If true (and if #ignore_attempts_to_set_nil), the setter works like Rail's #blank method: if it isn't blank, the instance variable is set. Def: true.
61
+ def self.configure
62
+ yield(configuration)
63
+ end
64
+
65
+ if File.exists?(CONFIG_LOCATION)
66
+ t = File.open(CONFIG_LOCATION)
67
+ elsif File.exists?(configuration.yaml_source_folder + 'cushion_defaults.yaml')
68
+ t = File.open(configuration.yaml_source_folder + 'cushion_defaults.yaml')
69
+ else
70
+ t = nil
71
+ end
72
+
73
+ config.from_hash(YAML::load(t)) if t
74
+
75
+ # Add class methods and set up +DefaultsHash+ when the module is included in a class.
76
+ #
77
+ # If +AUTO_LOAD_FROM_YAML+, then it also searches for a yaml configuration file for the class in the path specified
78
+ # in the config variables.
79
+ def self.included(base)
80
+
81
+ base.extend(ClassMethods)
82
+
83
+ if configuration.auto_load_from_yaml
84
+ base.defaults_from_yaml
85
+ else
86
+ base.initialize_defaults_hash
87
+ end
88
+ end
89
+
90
+ # Convenience method. If +x+ is a +Klass+, then +x#defaults+ returns +Klass.defaults+.
91
+ def defaults
92
+ self.class.defaults
93
+ end
94
+
95
+ # Convenience method. Returns the default value for :sym, going up the chain of cascaded defaults.
96
+ # *sym* :: Symbol representing the variable whose default value is desired.
97
+ def default(sym)
98
+ defaults[sym]
99
+ end
100
+
101
+ # Purely a convenience method.
102
+ def has_specified?(sym)
103
+ instance_variable_defined?("@#{sym}")
104
+ end
105
+
106
+ # 'Crystallize' the default: i.e., if this instance does not have +sym+ specified, then set the value of +sym+
107
+ # explicitly to the default value.
108
+ #
109
+ # This is most useful if you want to update the default value for +sym+ but do not want to affect one or more already
110
+ # exsiting instances of the class.
111
+ def crystallize_default(key, act_if_nilish=true)
112
+ key = key.to_sym
113
+ # crystallize if either (1) there is no value specified for :key, or (2) there is a value specified, but we are
114
+ # acting if a nilish value is specified and the value for :key is nilish.
115
+ if !has_specified? key || (act_if_nilish && CushionDefaults.nilish?(instance_variable_get("@#{key}")))
116
+ default_value = default(key)
117
+ instance_variable_set("@#{key}", default_value)
118
+ end
119
+ end
120
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cushion_defaults
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Mitchell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Allows you to specify a 'cushion' for various instance variables—effectively
14
+ a default value—that will be returned by optional reader methods if the instance
15
+ variable is undefined.
16
+ email: posgarou@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/cushion_defaults.rb
22
+ - lib/cushion_defaults/class_methods.rb
23
+ - lib/cushion_defaults/configuration.rb
24
+ - lib/cushion_defaults/defaults_hash.rb
25
+ homepage: http://rubygems.org/gems/cushion_defaults
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.4.3
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: An easy, flexible, and powerful alternative to hashes of defaults. Can be
49
+ used both in individual classes and in complex class hierarchies.
50
+ test_files: []