cushion_defaults 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: afcfd510eb6d2f7ceaa05cc1fdba5464b5c407ed
4
- data.tar.gz: 570e83a012861e042c33e582bf79fc29da25b383
3
+ metadata.gz: bacbeab26c1d40ab130cc3fb66b06a7e0eb26012
4
+ data.tar.gz: b056aa659f1279580225fa627482894ac8ac5e90
5
5
  SHA512:
6
- metadata.gz: 8e7f8f996945dd467466654fae31c8f62648cc3519738b9f97085787e3b7ea4a245e225b9b083509572cb40c443de9e23a0d94e1389e1ee70cedfd335409bbce
7
- data.tar.gz: a3d35fc0f44e465c22a0de9fa3576d6852ac6be3a5af34daf7227ee694da7e4be088071b2ce29e2f72ac849fc0936ac09dde07b042a187b809163afe5c9d7ba3
6
+ metadata.gz: 3d427f699e5ffb42d22c5e4cc7c2ae9817df5edeb347e984b0fff367924100defc1c8e30582f7ebcdead9b86006cd44a6bd5556357f096610335a80f25b4ed53
7
+ data.tar.gz: 4dca3355fac1a733c93d85511df0d943548774e65bc590300656b4d8cb141fa54f09282f180837924b83d8f3908488e314ff300a02272b7d83398e05260e3f07
data/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # CHANGELOG
2
+
3
+ ## 0.0.x
4
+
5
+ - 0.0.0: Initial version.
6
+ - 0.0.1
7
+ - Include MIT License.
8
+ - Specify GitHub homepage.
9
+ - 0.0.2
10
+ - Improve `cushion_reader` speed by approx. 15%.
11
+ - Specify Ruby version >= 2.0.0.
12
+ - 0.0.3
13
+ - Fix various bugs related to YAML config loading.
14
+ - Improve examples.
15
+
16
+ ## 0.1.x
17
+
18
+ - 0.1.0
19
+ - NEW FEATURE: Logging
20
+ - Add `config.record_in_log` (boolean), `config.log_lvl (int)`, and `config.logger` (Logger or similar) options.
21
+ - Add logging throughout the module at various levels.
22
+ - Logging enabled by default at info level.
23
+ - Improve performance of `cushion_reader` by approx. 115%.
24
+ - 0.1.1
25
+ - Greatly improve and expand documentation.
26
+ - Switch from rdoc to Yard
27
+
28
+ ## 0.2.x
29
+
30
+ - 0.2.0
31
+ - Place Configuration within the CushionDefaults module.
32
+ - IMPROVEMENT: `cushion_defaults.gemspec`
33
+ - Clarify and expand `cushion_defaults.gemspec`. Was insufficient before.
34
+ - Now specifies development dependencies.
35
+ - Add Gemfile for bundler
36
+ - IMPROVEMENT: Testing
37
+ - `test/` renamed to `spec/`
38
+ - Add `.rspec` and `spec/spec_helper.rb`
39
+ - Improve documentation further.
data/README.md ADDED
@@ -0,0 +1,331 @@
1
+ # Cushion Defaults
2
+ ## What Does It Do?
3
+
4
+ ### TL;DR
5
+
6
+ An easy, flexible, and powerful alternative to hashes of defaults. Can be used both in individual classes and in complex class hierarchies.
7
+
8
+ ### The Long Version
9
+
10
+ Allows you to specify a "cushion" for various instance variables—effectively a default value—that will be returned by optional reader methods if the instance variable is undefined.
11
+
12
+ If, for example, the default value for `@wheels` in class Car is 4 and we set up a new instance called `ford` (`ford = Car.new`), then calling `ford.wheels` will return 4—even though no instance variable `@wheels` has been directly specified for `ford`. And if we later change the default value of `wheels` for Car (`Car.defaults[:wheels] = 6`), then all subsequent calls to `ford.wheels` will return 6 (unless we crystallize it beforehand—see below for more details).
13
+
14
+ ## Why Should I Care?
15
+
16
+ 1. Don't Repeat Yourself (DRY): Gather your defaults in one place, and specify them only once.
17
+ 2. Correspondingly, minimize the amount of code you have to write and maintain. You'll be writing `x || default_value_for_x` a lot less—and if you later change the default value for x, you only have to update a single line of code.
18
+ 3. Easily allow subclasses to inherit the default values of their ancestor classes or override them with their own default values. CushionDefaults is in this respect more flexible than using either constants or `@@defaults` variables. As an added bonus, changes to the defaults of a superclass cascade down and affect the defaults of subclasses.
19
+ 4. Optionally, if you think of your defaults as configuration rather than logic, pull them out of your code and put them in class-specific YAML files that can be automatically loaded in.
20
+ 5. Using the YAML technique, you can maintain multiple sets of defaults and load in the appropriate one depending on the environment.
21
+ 6. If you follow the common pattern of setting instance variables to the default value (e.g., `@var = params[:var] || default_for_var`), you have no way of distinguishing between when `x@var` is set to the default value because that was actively selected (`params[:var]...`) and when it is set to the default because it otherwise would have been nil (`... || default_for_var`). This is especially important when defaults change occasionally (or even vary regularly!). CushionDefaults makes this situation easy to handle. Consider the following:
22
+
23
+ ```ruby
24
+ class Person
25
+ include CushionDefaults
26
+ self.defaults[:favorite_color] = 'blue'
27
+ cushion :favorite_color
28
+ end
29
+
30
+ ryan, julia = Person.new, Person.new
31
+ ryan.favorite_color = 'blue'
32
+
33
+ ryan.favorite_color # 'blue'
34
+ ryan.has_specified?(:favorite_color) # true
35
+ julia.favorite_color # 'blue'
36
+ julia.has_specified?(:favorite_color) # false
37
+
38
+ Person.defaults[:favorite_color] = 'green'
39
+
40
+ ryan.favorite_color # 'blue'
41
+ julia.favorite_color # 'green'
42
+ ```
43
+ ## How Do I Get It?
44
+ `gem install 'cushion_defaults'` if you just want the gem.
45
+
46
+ If you want to help out the project or edit the source code, clone the repository (hosted at [GitHub](https://github.com/posgarou/cushion_defaults)).
47
+ ## Give Me the Rundown
48
+ ### The Basics
49
+ Setting up a DefaultsHash, populating it, and setting up `cushion_reader`s and `cushion_writer`s is a simple process.
50
+
51
+ ```ruby
52
+ class Plant
53
+ include CushionDefaults
54
+ self.defaults = {color: 'green', sunlight_needed: 'full'}
55
+
56
+ # cushion_defaults is here equivalent to:
57
+ # cushion_reader :color, :sunlight_needed
58
+ # cushion_writer :color, :sunlight_needed
59
+ cushion_defaults
60
+
61
+ def needs_full_sunlight?
62
+ sunlight_needed.eql?('full')
63
+ end
64
+ end
65
+
66
+ rhododendron = Plant.new
67
+ rhododendron.color # 'green'
68
+ rhododendron.needs_full_sunlight? # true
69
+ ```
70
+
71
+ Now, if we later decide to place our Plant class within Brandon Sanderson's [Mistborn](http://brandonsanderson.com/books/mistborn/the-final-empire/) world, we may want to update our defaults:
72
+
73
+ ```ruby
74
+ Plant.defaults[:color] = 'brown'
75
+ ```
76
+
77
+ As soon as we do this, all Plants that do not have a color explicitly assigned will return the new default value when we call their `#color` method.
78
+
79
+ ```ruby
80
+ rhododendron.color # 'brown'
81
+ ```
82
+
83
+ ### Crystallizing Defaults
84
+ You can prevent this auto-updating, if desired, by calling `#crystallize_default` on those instances you don't want auto-updated. `#crystallize_default(sym)` effectively says "If no value for `@sym` is explicitly set, then explictly set it to the default value." Obviously, then, `#crystallize_default(sym)` affects only those instances that do not have a value explicitly specified for `sym`.
85
+
86
+ ```ruby
87
+ tulip, rose = Plant.new, Plant.new
88
+ tulip.color # 'brown'
89
+ rose.color = 'red'
90
+ tulip.has_specified?(:color) # false
91
+ rose.has_specified?(:color) # true
92
+
93
+ # crystallizes :color to 'brown'
94
+ tulip.crystallize_default(:color)
95
+
96
+ # has no effect, since :color is already set to 'red'
97
+ rose.crystallize_default(:color)
98
+
99
+ tulip.has_specified?(:color) # true
100
+
101
+ Plant.defaults[:color] = 'green'
102
+
103
+ tulip.color # 'brown'
104
+ rose.color # 'red'
105
+ Plant.new.color # 'green'
106
+ ```
107
+
108
+ ### Defaults and Inheritance
109
+ Classes inherit the defaults of those ancestors that respond to `#defaults` with a Hash or a descendent thereof.
110
+
111
+ This all takes place automatically. When CushionDefaults is included in a class, it automatically includes itself in all classes that subclass that class, and when a `cushion_reader` is called, it automatically moves up the class hierarchy if no value for the key is specified in the instance variable or in the current class.
112
+
113
+ ```ruby
114
+ class Klass
115
+ include CushionDefaults
116
+ self.defaults = {first: Klass, second: Klass, third: Klass}
117
+ cushion_defaults
118
+ end
119
+ class SubKlass < Klass
120
+ self.defaults += {second: SubKlass, fourth: SubKlass}
121
+ cushion :fourth
122
+ end
123
+ class SubSubKlass < SubKlass
124
+ self.defaults[:third] = SubSubKlass
125
+ end
126
+
127
+ x, y, z = Klass.new, SubKlass.new, SubSubKlass.new
128
+ z.first = 'custom'
129
+ ```
130
+
131
+ Calling `#first`, `#second`, `#third`, and `#fourth`, then, would produce the following results on x, y, and z:
132
+
133
+ ```ruby
134
+ puts [x.first, x.second, x.third]
135
+ # [Klass, Klass, Klass]
136
+ # x.fourth would return NoMethodError
137
+
138
+ puts [y.first, y.second, y.third, y.fourth]
139
+ # [Klass, SubKlass, Klass, SubKlass]
140
+
141
+ puts [z.first, z.second, z.third, z.fourth]
142
+ # ['custom', SubKlass, SubSubKlass, SubKlass]
143
+ ```
144
+
145
+ Obviously, changing the default of a parent class changes the value returned by subclass instances, unless they have explicitly overridden the default.
146
+
147
+ ```ruby
148
+ SubKlass.defaults[:second] = 'totally new value'
149
+ z.class # SubSubKlass, which < SubKlass
150
+ z.second # 'totally new value'
151
+ ```
152
+
153
+ ### Adding and Removing Readers and Writers
154
+ Now, if we were to later add a new default to Plant
155
+
156
+ ```ruby
157
+ Plant.defaults[:climate] = 'temperate'
158
+ ```
159
+
160
+ and ran
161
+
162
+ ```ruby
163
+ rhododendron.climate
164
+ ```
165
+
166
+ we would get a `NoMethodError`.
167
+
168
+ By default, CushionDefaults does not automatically add or remove readers and writers when defaults are added and removed. To change methods, you need to manually add readers and writers for the new default:
169
+
170
+ ```ruby
171
+ Plant.cushion :climate
172
+ ```
173
+
174
+ If at any point you want to manually remove the `cushion_reader` or `cushion_writer` for a class (although the need for this should be rare, as you can simply overwrite it), you can run the following:
175
+
176
+ ```ruby
177
+ Plant.remove_reader :climate
178
+ Plant.remove_writer :climate
179
+ ```
180
+
181
+ Alternatively, CushionDefaults can automatically add and remove methods for any new defaults added and any existing defaults removed. But to do that, we need to configure CushionDefaults.
182
+
183
+ ### Configuring CushionDefaults
184
+
185
+ There are two recommended techniques for configuring CushionDefaults (although a few other variations will work as well).
186
+
187
+ The simplest is to use `CushionDefaults.configure`, which yields a `CushionDefaults::Configuration` object that can be modified by a number of different methods, detailed in the docs.
188
+
189
+ ```ruby
190
+ CushionDefaults.configure do |conf|
191
+ conf.update_readers = true
192
+ conf.update_writers = true
193
+ end
194
+ ```
195
+
196
+ If the above `#configure` call is placed immediately after the require statement, then no explicit calls to `cushion`, `cushion_reader`, or `cushion_writer` are needed.
197
+
198
+ ```ruby
199
+ CushionDefaults.configure do |conf|
200
+ conf.update_readers = true
201
+ conf.update_writers = true
202
+ end
203
+
204
+ class Chair
205
+ include CushionDefaults
206
+ self.defaults = {material: 'wood', comfort_factor: 5}
207
+ end
208
+
209
+ dining_room_hardback = Chair.new
210
+ dining_room_hardback.comfort_factor = 3
211
+
212
+ dining_room_hardback.material # 'wood'
213
+ dining_room_hardback.comfort_factor # 3
214
+
215
+ # automatically adds #number_accomodated and #number_accomodated=, because of above-specified options
216
+ Chair.defaults[:number_accomodated] = 1
217
+
218
+ dining_room_hardback.number_accomodated # 1
219
+ ```
220
+
221
+ As an alternative to the `CushionDefaults.configure` block, you can define a cushion_defaults.yaml file. By default, CushionDefaults looks for this at `config/cushion_defaults.yaml` (relative either to the directory of the first file to require CushionDefaults or the gem's location in the file system). The YAML format is unremarkable, with the above `CushionDefaults.config do ... end` block equivalent to:
222
+
223
+ ```yaml
224
+ update_readers: true
225
+ update_writers: true
226
+ ```
227
+
228
+ ### Storing Class Defaults in YAML Files
229
+
230
+ By default, CushionDefaults checks for YAML files for each class but does not complain if no YAML files are found. (If you want it to complain, set `config.whiny_yaml` to true.)
231
+
232
+ CushionDefaults looks for these YAML files at `config/cushion_defaults/class_name.yaml`. For class Klass, then, it would expect a config file at `config/cushion_defaults/klass.yaml`. Classes in a namespace are expected to have their YAML files in a folder named after their namespace, e.g. Modjewel::Klass in `config/cushion_defaults/modjewel/klass.yaml`.
233
+
234
+ You can specify a different YAML source folder relative to the calling directory (`config/cushion_defaults/` by default) by setting `config.yaml_source_folder`, or you can specify an absolute path to the YAML source folder by setting `config.yaml_source_full_path`.
235
+
236
+ If you ever are bug-hunting and want to see where CushionDefaults expects a YAML file to be located, you can pass the class object to `config.yaml_file_for(klass)`.
237
+
238
+ These YAML files are loaded automatically (unless `config.auto_load_from_yaml` has been set to false). But if you ever want to (wipe and) reload the defaults for a class—or load for the first time if the above option is disabled—use the class method `defaults_from_yaml`.
239
+
240
+ ### Managing Multiple Class Defaults
241
+
242
+ #### Multiple Sets of Class Defaults
243
+
244
+ You can use the above techniques to maintain different sets of class defaults for all of your classes. This is especially useful if your application needs to run in different environments or regions. For a more complex (but still simple enough) example, see Example 4 in the examples folder. Following is a trivial example.
245
+
246
+ ```ruby
247
+ class Season
248
+ # Obviously this is only meteorological seasons, and only valid for the Northern hemisphere
249
+ attr_accessor :months, :short_code
250
+ def initialize(&block)
251
+ yield(self) if block_given?
252
+ end
253
+ def include?(date)
254
+ months.include?(date.month)
255
+ end
256
+ def yaml_source_path
257
+ "config/cushion_defaults/#{short_code}/"
258
+ end
259
+ end
260
+ seasons = [
261
+ Season.new {|s| s.months=[3,4,5]; s.short_code='spr'},
262
+ Season.new {|s| s.months=[6,7,8]; s.short_code='sum'},
263
+ Season.new {|s| s.months=[9,10,11]; s.short_code='fal'},
264
+ Season.new {|s| s.months=[12,1,2]; s.short_code='win'}
265
+ ]
266
+ current_season = seasons.select{|s| s.include?(Date.today)}.first
267
+ CushionDefaults.configure {|conf| conf.yaml_source_path = current_season.yaml_source_path}
268
+ ```
269
+
270
+ The above will set the root directory for all class defaults, depending on the current date, to one of the following: `config/cushion_defaults/spr/`, `config/cushion_defaults/sum/`, `config/cushion_defaults/fal/`, or `config/cushion_defaults/win/`.
271
+
272
+ #### Multiple Defaults for a Single Class
273
+
274
+ Alternatively, if there is only a single class whose defaults you would like to load in one of several forms, you can do something like the following:
275
+
276
+ ```ruby
277
+ # select a random language
278
+ current_lang = ['en','fr','de'].sample
279
+ class Person
280
+ include CushionDefaults
281
+ defaults_from_yaml "#{self.to_s}_#{current_lang}"
282
+ cushion_defaults
283
+ end
284
+ ```
285
+
286
+ In this example, we load (randomly) either `person_en.yaml`, `person_fr.yaml`, or `person_de.yaml`.
287
+
288
+ ### Pushy and Polite Defaults
289
+
290
+ Pushy and polite defaults are an experimental feature. Rough documentation can be found in the docs, and more details will be forthcoming.
291
+
292
+ ### Testing and Bug Fixing
293
+
294
+ The most common testing configuration options are available by calling `config.testing!`.
295
+
296
+ You may find the following methods helpful in testing and bug fixing:
297
+
298
+ - `instance#has_specified?(sym)`: returns true if the instance has the instance variable denoted by `sym` defined
299
+ - `defaults#ish_keys`: returns the keys of both its defaults and those it inherits from its parents
300
+ - `defaults#has_ish_key?(key)`: returns true if `key` is an ish_key.
301
+ - `defaults#where_is_that_default_again(sym)`: returns the closest ancestor class in which `sym` is defined as a default. If no ancestor class has it defined as a default, returns `nil`.
302
+
303
+ ## But I need...
304
+
305
+ If you need more than CushionDefaults offers right now, you've got a couple different options:
306
+
307
+ 1. Suggest a feature. Please explain why you think this feature would be valuable, and offer a couple different use cases to showcase how it would help people.
308
+ 2. Code a feature. Fork and pull, and I'll fold it in and implement it if it looks solid and generally useful.
309
+ 3. Check out Cascading Configuration. You may want to check out [Cascading Configuration](https://github.com/RidiculousPower/cascading_configuration), which tackles a similar problem but offers a different approach and featureset.
310
+
311
+ ## Feedback
312
+
313
+ Any feedback is very much appreciated!
314
+
315
+ ###Bugs
316
+
317
+ Run into any bugs or issues? Please report them on the [GitHub issue tracker](https://github.com/posgarou/cushion_defaults/issues).
318
+
319
+ ###Like It?
320
+
321
+ 1. Tell a friend.
322
+ 2. Star or [fork](https://github.com/posgarou/cushion_defaults/fork) the [GitHub repository](https://github.com/posgarou/cushion_defaults).
323
+ 3. If you're feeling generous, [offer a tip](https://gratipay.com/posgarou/).
324
+
325
+ ###Not Sold?
326
+
327
+ If you have the time, tell me why.
328
+
329
+ Not a useful concept? Don't like the implementation? Think the default configuration options should be different? Edit [the wiki](https://github.com/posgarou/cushion_defaults/wiki) and let me know.
330
+
331
+ If you have any specific suggestions for how to make CushionDefaults better, I'd love to hear them.
@@ -27,7 +27,7 @@ require 'cushion_defaults/defaults_hash'
27
27
  module CushionDefaults
28
28
 
29
29
  # Version constant
30
- VERSION = '0.1.1'
30
+ VERSION = '0.2.0'
31
31
 
32
32
  # The path of the first file that +includes+ CushionDefaults.
33
33
  CALLING_PATH = File.expand_path(File.dirname($0)) + '/'
@@ -1,199 +1,199 @@
1
1
  require 'logger'
2
2
 
3
- # TODO Place in module CushionDefaults--dumb mistake
4
-
5
- # Effectively a singleton class, +Configuration+ keeps track of various configuration options for +CushionDefaults+.
6
- #
7
- # In addition, it also keeps track of certain state data for +CushionDefaults+.
8
- #
9
- # For configuration options, see the attribute writers.
10
- #
11
- class Configuration
12
- # adapted from http://brandonhilkert.com/blog/ruby-gem-configuration-patterns/
13
-
14
- # @return [boolean] true if readers should automatically be added, false otherwise. Def. false.
15
- attr_accessor :update_readers
16
-
17
- # @return [boolean] true if writers should automatially be added, false otherwise. Def. false.
18
- attr_accessor :update_writers
19
-
20
- # @return [boolean] true if CushionDefaults should automatically check whether a YAML file exists for each class that
21
- # includes it, false otherwise. Def. true.
22
- # @see ClassMethods.defaults_from_yaml defauls_from_yaml
23
- attr_accessor :auto_load_from_yaml
24
-
25
- # @return [string] the location, relative to the directory of the first file to include CushionDefaults, where YAML
26
- # config files are looked for by default. Def. 'config/cushion_defaults/'
27
- attr_accessor :yaml_source_folder
28
-
29
- # @return [string] the full path to the directory where YAML config files are looked for. If specified, this overrides
30
- # {#yaml_source_folder}. Def. nil.
31
- attr_writer :yaml_source_full_path
32
-
33
- # @return [boolean] if true, CushionDefaults makes log entries. Def. true.
34
- attr_accessor :record_in_log
35
-
36
- # @return [boolean] if true, CushionDefaults will complain (warning level) when it cannot find a YAML configuration
37
- # file for a class. If false, it only posts this message at the debug level. Def. false.
38
- attr_accessor :whiny_yaml
39
-
40
- # @return [boolean] if true, calls to cushion_writer methods will not set the instance variable if the value passed in
41
- # is nil (thus allowing cushion_reader to still return the default value, rather than nil). Def. true.
42
- # @example Ignored Call to cushion_writer When ignore_attempts_to_set_nil == true
43
- # obj.var = nil # has no effect
44
- # obj.var # 'default value'
45
- # @see blank_str_is_nil
46
- attr_accessor :ignore_attempts_to_set_nil
47
-
48
- # @return [boolean] if true, cushion_writers will also not record blank strings. Has no effect if
49
- # {#ignore_attempts_to_set_nil} is false. Def. true.
50
- # @example Ignored Call to cushion_writer When blank_str_is_nil == false
51
- # obj.var = '' # has no effect
52
- # obj.var # 'default value'
53
- attr_accessor :blank_str_is_nil
54
-
55
- # @return [boolean] if true, cushion_writers will issue a warning when you attempt to set an instance variable to
56
- # nil or '' (as applicable). Has no effect if {#ignore_attempts_to_set_nil} == false. Def. false.
57
- attr_accessor :whiny_ignores
58
-
59
- # Has no effect.
60
- # @deprecated
61
- attr_accessor :cushion_child_defaults_in_parent
62
-
63
- # @return [Logger] returns the Logger object to which CushionDefaults sends log entries.
64
- attr_reader :logger
65
-
66
- # Initializes with the values specified in {#defaults!}
67
- def initialize
68
- defaults!
69
- @we_have_a_pushy = false
70
- end
3
+ module CushionDefaults
4
+ # Effectively a singleton class, +Configuration+ keeps track of various configuration options for +CushionDefaults+.
5
+ #
6
+ # In addition, it also keeps track of certain state data for +CushionDefaults+.
7
+ #
8
+ # For configuration options, see the attribute writers.
9
+ #
10
+ class Configuration
11
+ # adapted from http://brandonhilkert.com/blog/ruby-gem-configuration-patterns/
12
+
13
+ # @return [boolean] true if readers should automatically be added, false otherwise. Def. false.
14
+ attr_accessor :update_readers
15
+
16
+ # @return [boolean] true if writers should automatially be added, false otherwise. Def. false.
17
+ attr_accessor :update_writers
18
+
19
+ # @return [boolean] true if CushionDefaults should automatically check whether a YAML file exists for each class that
20
+ # includes it, false otherwise. Def. true.
21
+ # @see ClassMethods.defaults_from_yaml defauls_from_yaml
22
+ attr_accessor :auto_load_from_yaml
23
+
24
+ # @return [string] the location, relative to the directory of the first file to include CushionDefaults, where YAML
25
+ # config files are looked for by default. Def. 'config/cushion_defaults/'
26
+ attr_accessor :yaml_source_folder
27
+
28
+ # @return [string] the full path to the directory where YAML config files are looked for. If specified, this overrides
29
+ # {#yaml_source_folder}. Def. nil.
30
+ attr_writer :yaml_source_full_path
31
+
32
+ # @return [boolean] if true, CushionDefaults makes log entries. Def. true.
33
+ attr_accessor :record_in_log
34
+
35
+ # @return [boolean] if true, CushionDefaults will complain (warning level) when it cannot find a YAML configuration
36
+ # file for a class. If false, it only posts this message at the debug level. Def. false.
37
+ attr_accessor :whiny_yaml
38
+
39
+ # @return [boolean] if true, calls to cushion_writer methods will not set the instance variable if the value passed in
40
+ # is nil (thus allowing cushion_reader to still return the default value, rather than nil). Def. true.
41
+ # @example Ignored Call to cushion_writer When ignore_attempts_to_set_nil == true
42
+ # obj.var = nil # has no effect
43
+ # obj.var # 'default value'
44
+ # @see blank_str_is_nil
45
+ attr_accessor :ignore_attempts_to_set_nil
46
+
47
+ # @return [boolean] if true, cushion_writers will also not record blank strings. Has no effect if
48
+ # {#ignore_attempts_to_set_nil} is false. Def. true.
49
+ # @example Ignored Call to cushion_writer When blank_str_is_nil == false
50
+ # obj.var = '' # has no effect
51
+ # obj.var # 'default value'
52
+ attr_accessor :blank_str_is_nil
53
+
54
+ # @return [boolean] if true, cushion_writers will issue a warning when you attempt to set an instance variable to
55
+ # nil or '' (as applicable). Has no effect if {#ignore_attempts_to_set_nil} == false. Def. false.
56
+ attr_accessor :whiny_ignores
57
+
58
+ # Has no effect.
59
+ # @deprecated
60
+ attr_accessor :cushion_child_defaults_in_parent
61
+
62
+ # @return [Logger] returns the Logger object to which CushionDefaults sends log entries.
63
+ attr_reader :logger
64
+
65
+ # Initializes with the values specified in {#defaults!}
66
+ def initialize
67
+ defaults!
68
+ @we_have_a_pushy = false
69
+ end
71
70
 
72
- # @!attribute [r] yaml_source_full_path
73
- # Returns or computes the folder where class-specific yaml files are expected to reside.
74
- # @return [String] path to yaml config files.
75
- def yaml_source_full_path
76
- @yaml_source_full_path || CushionDefaults::CALLING_PATH + yaml_source_folder
77
- end
71
+ # @!attribute [r] yaml_source_full_path
72
+ # Returns or computes the folder where class-specific yaml files are expected to reside.
73
+ # @return [String] path to yaml config files.
74
+ def yaml_source_full_path
75
+ @yaml_source_full_path || CushionDefaults::CALLING_PATH + yaml_source_folder
76
+ end
78
77
 
79
- # Update configuration options with those values contained within +loaded_config+.
80
- #
81
- # @param loaded_config [Hash] hash of config options and settings
82
- def from_hash(loaded_config)
83
- log_str = 'Loading configuration options from hash...'
84
- loaded_config.each do |key, val|
85
- log_str << "\n\t\t#{key}: #{val}"
86
- # We need to be able to use some of the checks and responses in the custom setter methods
87
- writer_sym = "#{key}=".to_sym
88
- send writer_sym, val if respond_to? writer_sym
89
- #instance_variable_set("@#{key.to_sym}", val) if instance_variable_defined? "@#{key.to_sym}"
78
+ # Update configuration options with those values contained within +loaded_config+.
79
+ #
80
+ # @param loaded_config [Hash] hash of config options and settings
81
+ def from_hash(loaded_config)
82
+ log_str = 'Loading configuration options from hash...'
83
+ loaded_config.each do |key, val|
84
+ log_str << "\n\t\t#{key}: #{val}"
85
+ # We need to be able to use some of the checks and responses in the custom setter methods
86
+ writer_sym = "#{key}=".to_sym
87
+ send writer_sym, val if respond_to? writer_sym
88
+ #instance_variable_set("@#{key.to_sym}", val) if instance_variable_defined? "@#{key.to_sym}"
89
+ end
90
+ CushionDefaults.log(log_str, :info)
90
91
  end
91
- CushionDefaults.log(log_str, :info)
92
- end
93
92
 
94
- # Sets or resets configuration object to default configuration settings.
95
- def defaults!
96
- self.update_readers = false
97
- self.update_writers = false
98
- self.auto_load_from_yaml = true
99
- self.yaml_source_folder = 'config/cushion_defaults/'
100
- self.yaml_source_full_path = nil
101
- self.record_in_log = true
102
- self.logger = Logger.new $stdout
103
- self.log_lvl = Logger::INFO
104
- self.whiny_yaml = false
105
- self.whiny_ignores = false
106
- self.ignore_attempts_to_set_nil = true
107
- self.blank_str_is_nil = true
108
- end
93
+ # Sets or resets configuration object to default configuration settings.
94
+ def defaults!
95
+ self.update_readers = false
96
+ self.update_writers = false
97
+ self.auto_load_from_yaml = true
98
+ self.yaml_source_folder = 'config/cushion_defaults/'
99
+ self.yaml_source_full_path = nil
100
+ self.record_in_log = true
101
+ self.logger = Logger.new $stdout
102
+ self.log_lvl = Logger::INFO
103
+ self.whiny_yaml = false
104
+ self.whiny_ignores = false
105
+ self.ignore_attempts_to_set_nil = true
106
+ self.blank_str_is_nil = true
107
+ end
109
108
 
110
- # Sets configuration object to most common testing (and development) options.
111
- def test_settings!
112
- defaults!
113
- self.whiny_yaml = true
114
- self.whiny_ignores = true
115
- self.log_lvl = Logger::DEBUG
116
- end
109
+ # Sets configuration object to most common testing (and development) options.
110
+ def test_settings!
111
+ defaults!
112
+ self.whiny_yaml = true
113
+ self.whiny_ignores = true
114
+ self.log_lvl = Logger::DEBUG
115
+ end
117
116
 
118
- # @!attribute [w] logger
119
- # Sets @logger to either a different Logger or another object that implements roughly the same interface. Note
120
- # that only minimal checking is done to ensure the interface is implemented, and passing in an object with an
121
- # incomplete implementation of the interface will cause errors. If you want to disable logging, you should instead
122
- # set {#record_in_log} to false.
123
- # @see #record_in_log
124
- def logger=(new_logger)
125
- if new_logger.nil?
126
- self.record_in_log = false
127
- @logger = nil
128
- else
129
- if new_logger.respond_to? :info
130
- @logger = new_logger
131
- assign_formatter_to_logger
117
+ # @!attribute [w] logger
118
+ # Sets @logger to either a different Logger or another object that implements roughly the same interface. Note
119
+ # that only minimal checking is done to ensure the interface is implemented, and passing in an object with an
120
+ # incomplete implementation of the interface will cause errors. If you want to disable logging, you should instead
121
+ # set {#record_in_log} to false.
122
+ # @see #record_in_log
123
+ def logger=(new_logger)
124
+ if new_logger.nil?
125
+ self.record_in_log = false
126
+ @logger = nil
132
127
  else
133
- CushionDefaults.log("config.logger not set to #{new_logger}, as it does not appear to implement standard logging methods.", :error)
128
+ if new_logger.respond_to? :info
129
+ @logger = new_logger
130
+ assign_formatter_to_logger
131
+ else
132
+ CushionDefaults.log("config.logger not set to #{new_logger}, as it does not appear to implement standard logging methods.", :error)
133
+ end
134
134
  end
135
135
  end
136
- end
137
136
 
138
- # CamelCase to underscores
139
- # @param s [String] CamelCase
140
- # @return [String] underscored version of s
141
- def underscore(s)
142
- s.gsub(/::/, '/').
143
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
144
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
145
- tr("-", "_").
146
- downcase
147
- end
137
+ # CamelCase to underscores
138
+ # @param s [String] CamelCase
139
+ # @return [String] underscored version of s
140
+ def underscore(s)
141
+ s.gsub(/::/, '/').
142
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
143
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
144
+ tr("-", "_").
145
+ downcase
146
+ end
148
147
 
149
- # Expected YAML location for a class.
150
- # @param klass [Class] class in question.
151
- # @return [String] expected path to the YAML file
152
- def yaml_file_for(klass)
153
- "#{CushionDefaults::configuration.yaml_source_full_path}#{underscore(klass.to_s)+'.yaml'}"
154
- end
148
+ # Expected YAML location for a class.
149
+ # @param klass [Class] class in question.
150
+ # @return [String] expected path to the YAML file
151
+ def yaml_file_for(klass)
152
+ "#{CushionDefaults::configuration.yaml_source_full_path}#{underscore(klass.to_s)+'.yaml'}"
153
+ end
155
154
 
156
- # @!attribute [w] log_lvl
157
- # Set the level of logging. Alias of logger.level=. 0: debug, 1: info, 2: warn, 3: error, 4: fatal, 5: unknown
158
- def log_lvl=(lvl)
159
- if @logger
160
- @logger.level = lvl
155
+ # @!attribute [w] log_lvl
156
+ # Set the level of logging. Alias of logger.level=. 0: debug, 1: info, 2: warn, 3: error, 4: fatal, 5: unknown
157
+ def log_lvl=(lvl)
158
+ if @logger
159
+ @logger.level = lvl
160
+ end
161
161
  end
162
- end
163
162
 
164
- # @!attribute [r] we_have_a_pushy
165
- # Denotes whether (over the life of the program) any defaults have been marked pushy.
166
- # In the future, this may instead denote whether any defaults are *currently* marked as pushy.
167
- # @return [boolean] true if a pushy was set at any time
168
- # @api private
169
- def we_have_a_pushy?
170
- @we_have_a_pushy
171
- end
163
+ # @!attribute [r] we_have_a_pushy
164
+ # Denotes whether (over the life of the program) any defaults have been marked pushy.
165
+ # In the future, this may instead denote whether any defaults are *currently* marked as pushy.
166
+ # @return [boolean] true if a pushy was set at any time
167
+ # @api private
168
+ def we_have_a_pushy?
169
+ @we_have_a_pushy
170
+ end
172
171
 
173
- # Opposite of {#we_have_a_pushy?}
174
- # @return [boolean] true if no pushies have been set over the life of the program
175
- # @api private
176
- def no_pushies?
177
- # Note that if you add a pushy, and then remove it, this will still return false. Basically, the method returns
178
- # whether there was, at any point in time, a pushy default.
179
- #
180
- # The whole handling of pushies can and will be improved in the future.
181
- !@we_have_a_pushy
182
- end
172
+ # Opposite of {#we_have_a_pushy?}
173
+ # @return [boolean] true if no pushies have been set over the life of the program
174
+ # @api private
175
+ def no_pushies?
176
+ # Note that if you add a pushy, and then remove it, this will still return false. Basically, the method returns
177
+ # whether there was, at any point in time, a pushy default.
178
+ #
179
+ # The whole handling of pushies can and will be improved in the future.
180
+ !@we_have_a_pushy
181
+ end
183
182
 
184
- # Declares that a pushy default has been set.
185
- # @api private
186
- def we_have_a_pushy!
187
- @we_have_a_pushy = true
188
- end
183
+ # Declares that a pushy default has been set.
184
+ # @api private
185
+ def we_have_a_pushy!
186
+ @we_have_a_pushy = true
187
+ end
189
188
 
190
- protected
189
+ protected
191
190
 
192
- # Specifies the formatter for logger. Will not be called if a logger is assigned with +should_assign_formatter+ set to
193
- # false.
194
- def assign_formatter_to_logger
195
- logger.formatter = proc do |severity, time, progname, msg|
196
- "\nCUSHIONDEFAULTS: #{severity}\n\t\##{progname ? "#{progname} at" : "At"} #{time.strftime('%d %b %Y, %H:%M:%S%p')}\n\t#{msg}\n"
191
+ # Specifies the formatter for logger. Will not be called if a logger is assigned with +should_assign_formatter+ set to
192
+ # false.
193
+ def assign_formatter_to_logger
194
+ logger.formatter = proc do |severity, time, progname, msg|
195
+ "\nCUSHIONDEFAULTS: #{severity}\n\t\##{progname ? "#{progname} at" : "At"} #{time.strftime('%d %b %Y, %H:%M:%S%p')}\n\t#{msg}\n"
196
+ end
197
197
  end
198
198
  end
199
199
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cushion_defaults
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Mitchell
@@ -9,15 +9,47 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2014-12-09 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: yard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.8'
13
41
  description: Allows you to specify a 'cushion' for various instance variables—effectively
14
42
  a default value—that will be returned by optional reader methods if the instance
15
43
  variable is undefined.
16
44
  email: posgarou@gmail.com
17
45
  executables: []
18
46
  extensions: []
19
- extra_rdoc_files: []
47
+ extra_rdoc_files:
48
+ - README.md
49
+ - CHANGELOG.md
20
50
  files:
51
+ - CHANGELOG.md
52
+ - README.md
21
53
  - lib/cushion_defaults.rb
22
54
  - lib/cushion_defaults/class_methods.rb
23
55
  - lib/cushion_defaults/configuration.rb
@@ -26,8 +58,12 @@ homepage: https://github.com/posgarou/cushion_defaults
26
58
  licenses:
27
59
  - MIT
28
60
  metadata: {}
29
- post_install_message:
30
- rdoc_options: []
61
+ post_install_message: |-
62
+ Thanks for installing CushionDefaults!
63
+ For a quick overview, check out the README and examples/ folder.
64
+ rdoc_options:
65
+ - "--main"
66
+ - README.md
31
67
  require_paths:
32
68
  - lib
33
69
  required_ruby_version: !ruby/object:Gem::Requirement