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 +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: []
|