cushion_defaults 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/cushion_defaults/class_methods.rb +189 -0
- data/lib/cushion_defaults/configuration.rb +56 -0
- data/lib/cushion_defaults/defaults_hash.rb +165 -0
- data/lib/cushion_defaults.rb +120 -0
- metadata +50 -0
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: []
|