cushion_defaults 0.0.3 → 0.1.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 +4 -4
- data/lib/cushion_defaults/class_methods.rb +25 -12
- data/lib/cushion_defaults/configuration.rb +65 -2
- data/lib/cushion_defaults/defaults_hash.rb +11 -1
- data/lib/cushion_defaults.rb +48 -26
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ee8cdd20d451d7e48d28f67f87161138e5b4c87
|
4
|
+
data.tar.gz: beccbd9d7f439691d120f23e74512be56d480b96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 240abcc508735adc2eec294ccb1851609b2925e6f90d280b9108d6860c50cf50d064a37cc7df5dea5f269e690e7ec84dea9cee7d8c5117c566958139c624053a
|
7
|
+
data.tar.gz: 0f12017c5d6b9aa2076fff84c69cb343bc3466102f275e13f5077c70df6236d74f132c36c6bc80eb2437de91dd3f60bdc49ecd3c0e3d0da0da6cf4b9e2bddba6
|
@@ -7,10 +7,9 @@ module CushionDefaults
|
|
7
7
|
|
8
8
|
# Either set up or wipe @defaults. Should not usually be called directly.
|
9
9
|
def initialize_defaults_hash
|
10
|
-
|
11
10
|
if @defaults
|
12
11
|
# We need to maintain the identity of the hash, as child classes may have stored a reference to it
|
13
|
-
@defaults.
|
12
|
+
@defaults.clear
|
14
13
|
else
|
15
14
|
@defaults = DefaultsHash.new(self)
|
16
15
|
end
|
@@ -25,7 +24,9 @@ module CushionDefaults
|
|
25
24
|
def defaults=(replacement_hash)
|
26
25
|
# Need to copy over keys/vals to ensure @defaults remains a DefaultsHash and retains identity
|
27
26
|
|
27
|
+
CushionDefaults.log("Old defaults deleted for #{self}:#{@defaults.reduce(''){|s,(k,v)| s+"\n\t\t#{k}: #{v}"}}", :info) unless @defaults.empty?
|
28
28
|
@defaults.replace(replacement_hash)
|
29
|
+
CushionDefaults.log("New defaults added for #{self}:#{@defaults.reduce(''){|s,(k,v)| s+"\n\t\t#{k}: #{v}"}}", :info)
|
29
30
|
@defaults.keys.each do |key|
|
30
31
|
unless key.is_a? Symbol
|
31
32
|
@defaults[key.to_sym] = @defaults[key].delete!
|
@@ -54,15 +55,18 @@ module CushionDefaults
|
|
54
55
|
|
55
56
|
yaml = YAML::load(File.open(yaml_path)) rescue {}
|
56
57
|
|
57
|
-
if yaml.empty?
|
58
|
-
|
58
|
+
if yaml.empty?
|
59
|
+
CushionDefaults.log("No YAML configuration for class #{self} found at #{yaml_path}", CushionDefaults.conf.whiny_yaml ? :warn : :debug)
|
59
60
|
end
|
60
61
|
|
61
62
|
initialize_defaults_hash
|
63
|
+
log_str = "New defaults added for #{self}:"
|
62
64
|
# If automatic readers and writers are enabled, this will set them up as a consequence.
|
63
65
|
yaml.each do |key, val|
|
66
|
+
log_str << "\n\t\t#{key}: #{val}"
|
64
67
|
@defaults[key.to_sym] = val
|
65
68
|
end
|
69
|
+
CushionDefaults.log(log_str, :info)
|
66
70
|
end
|
67
71
|
|
68
72
|
# Sets up a conditional getter method for each :sym in +syms+.
|
@@ -77,16 +81,17 @@ module CushionDefaults
|
|
77
81
|
sym = sym.to_sym
|
78
82
|
sym_str = sym.to_s
|
79
83
|
if self_or_parent_instance_method?(sym)
|
80
|
-
|
84
|
+
CushionDefaults.log("#{self} or a parent class already has what looks like a getter method for #{sym_str}", :warn)
|
81
85
|
end
|
82
86
|
instance_variable_string = "@#{sym_str}"
|
83
87
|
define_method(sym) do
|
84
|
-
if
|
88
|
+
if instance_variable_defined?(instance_variable_string) && (CushionDefaults.conf.no_pushies? || defaults.not_pushy?(sym))
|
85
89
|
instance_variable_get(instance_variable_string)
|
86
90
|
else
|
87
91
|
defaults[sym]
|
88
92
|
end
|
89
93
|
end
|
94
|
+
CushionDefaults.log("cushion_reader #{sym} established for #{self}")
|
90
95
|
end
|
91
96
|
end
|
92
97
|
|
@@ -94,7 +99,7 @@ module CushionDefaults
|
|
94
99
|
syms.each do |sym|
|
95
100
|
method_name = "#{sym}="
|
96
101
|
if self_or_parent_instance_method?(method_name)
|
97
|
-
|
102
|
+
CushionDefaults.log("#{self} or a parent class already has what looks like a setter method for #{sym}", :warn)
|
98
103
|
end
|
99
104
|
|
100
105
|
instance_variable_string = "@#{sym}"
|
@@ -102,26 +107,33 @@ module CushionDefaults
|
|
102
107
|
define_method(method_name) do |y|
|
103
108
|
if CushionDefaults.nilish? y
|
104
109
|
if CushionDefaults.conf.whiny_ignores
|
105
|
-
|
110
|
+
CushionDefaults.log("You are attempting to set a nilish value for #{sym}. This will not be recorded, and any value set will be deleted.", :warn)
|
106
111
|
end
|
107
112
|
remove_instance_variable(instance_variable_string) if instance_variable_defined?(instance_variable_string)
|
108
113
|
else
|
109
|
-
if defaults.pushy?(sym)
|
110
|
-
|
114
|
+
if CushionDefaults.conf.we_have_a_pushy? && defaults.pushy?(sym)
|
115
|
+
CushionDefaults.log("You are setting a value for #{sym}, but this is a pushy default and this value will not be returned by any cushion_readers.", :warn)
|
111
116
|
end
|
112
117
|
instance_variable_set(instance_variable_string, y)
|
113
118
|
end
|
114
119
|
end
|
120
|
+
CushionDefaults.log("cushion_writer #{sym}= established for #{self}")
|
115
121
|
end
|
116
122
|
end
|
117
123
|
|
118
124
|
def remove_reader(sym)
|
119
|
-
|
125
|
+
if self_has_method?(sym)
|
126
|
+
undef_method(sym)
|
127
|
+
CushionDefaults.log("cushion_reader #{sym} removed from #{self}", :info)
|
128
|
+
end
|
120
129
|
end
|
121
130
|
|
122
131
|
def remove_writer(sym)
|
123
132
|
write_sym = "#{sym}=".to_sym
|
124
|
-
|
133
|
+
if self_has_method?(write_sym)
|
134
|
+
undef_method(write_sym)
|
135
|
+
CushionDefaults.log("cushion_writer #{sym}= removed from #{self}", :info)
|
136
|
+
end
|
125
137
|
end
|
126
138
|
|
127
139
|
# Sets up both +conditional_getters+ and normal +attr_writer+ for +syms+.
|
@@ -156,6 +168,7 @@ module CushionDefaults
|
|
156
168
|
# - #cushion_readers_for_defaults
|
157
169
|
def cushion_defaults
|
158
170
|
cushion *defaults.keys
|
171
|
+
CushionDefaults.log("cushions established for #{self}'s defaults': #{defaults.keys.join(', ')}", :info)
|
159
172
|
end
|
160
173
|
|
161
174
|
def make_pushy(*syms)
|
@@ -1,12 +1,20 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
1
3
|
# Effectively a singleton class, +Configuration+ keeps track of various configuration options for +CushionDefaults+.
|
4
|
+
#
|
5
|
+
# In addition, it also keeps track of certain state data for +CushionDefaults+.
|
2
6
|
class Configuration # :nodoc:
|
3
7
|
# adapted from http://brandonhilkert.com/blog/ruby-gem-configuration-patterns/
|
4
8
|
|
5
|
-
attr_accessor :update_readers, :update_writers, :auto_load_from_yaml, :yaml_source_folder, :yaml_source_full_path
|
9
|
+
attr_accessor :update_readers, :update_writers, :auto_load_from_yaml, :yaml_source_folder, :yaml_source_full_path
|
10
|
+
attr_accessor :record_in_log, :whiny_yaml, :whiny_ignores, :cushion_child_defaults_in_parent, :ignore_attempts_to_set_nil
|
11
|
+
attr_accessor :blank_str_is_nil
|
12
|
+
attr_reader :logger
|
6
13
|
|
7
14
|
# Initializes with +#defaults+
|
8
15
|
def initialize
|
9
16
|
defaults!
|
17
|
+
@we_have_a_pushy = false
|
10
18
|
end
|
11
19
|
|
12
20
|
# Returns or computes the folder where class-specific yaml files are expected to reside.
|
@@ -18,9 +26,15 @@ class Configuration # :nodoc:
|
|
18
26
|
#
|
19
27
|
# +loaded_config+ :: hash from which options will be derived
|
20
28
|
def from_hash(loaded_config)
|
29
|
+
log_str = 'Loading configuration options from hash...'
|
21
30
|
loaded_config.each do |key, val|
|
22
|
-
|
31
|
+
log_str << "\n\t\t#{key}: #{val}"
|
32
|
+
# We need to be able to use some of the checks and responses in the custom setter methods
|
33
|
+
writer_sym = "#{key}=".to_sym
|
34
|
+
send writer_sym, val if respond_to? writer_sym
|
35
|
+
#instance_variable_set("@#{key.to_sym}", val) if instance_variable_defined? "@#{key.to_sym}"
|
23
36
|
end
|
37
|
+
CushionDefaults.log(log_str, :info)
|
24
38
|
end
|
25
39
|
|
26
40
|
# Defines default configuration settings
|
@@ -30,6 +44,9 @@ class Configuration # :nodoc:
|
|
30
44
|
self.auto_load_from_yaml = true
|
31
45
|
self.yaml_source_folder = 'config/cushion_defaults/'
|
32
46
|
self.yaml_source_full_path = nil
|
47
|
+
self.record_in_log = true
|
48
|
+
self.logger = Logger.new $stdout
|
49
|
+
self.log_lvl = Logger::INFO
|
33
50
|
self.whiny_yaml = false
|
34
51
|
self.whiny_ignores = false
|
35
52
|
self.ignore_attempts_to_set_nil = true
|
@@ -40,6 +57,21 @@ class Configuration # :nodoc:
|
|
40
57
|
defaults!
|
41
58
|
self.whiny_yaml = true
|
42
59
|
self.whiny_ignores = true
|
60
|
+
self.log_lvl = Logger::DEBUG
|
61
|
+
end
|
62
|
+
|
63
|
+
def logger=(new_logger, should_assign_formatter=true)
|
64
|
+
if new_logger.nil?
|
65
|
+
self.record_in_log = false
|
66
|
+
@logger = nil
|
67
|
+
else
|
68
|
+
if new_logger.respond_to? :info
|
69
|
+
@logger = new_logger
|
70
|
+
assign_formatter_to_logger if should_assign_formatter
|
71
|
+
else
|
72
|
+
CushionDefaults.log("config.logger not set to #{new_logger}, as it does not appear to implement standard logging methods.", :error)
|
73
|
+
end
|
74
|
+
end
|
43
75
|
end
|
44
76
|
|
45
77
|
def underscore(s)
|
@@ -53,4 +85,35 @@ class Configuration # :nodoc:
|
|
53
85
|
def yaml_file_for(klass)
|
54
86
|
"#{CushionDefaults::configuration.yaml_source_full_path}#{underscore(klass.to_s)+'.yaml'}"
|
55
87
|
end
|
88
|
+
|
89
|
+
def log_lvl=(lvl)
|
90
|
+
if @logger
|
91
|
+
@logger.level = lvl
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def we_have_a_pushy?
|
96
|
+
@we_have_a_pushy
|
97
|
+
end
|
98
|
+
|
99
|
+
def no_pushies?
|
100
|
+
# Note that if you add a pushy, and then remove it, this will still return false. Basically, the method returns
|
101
|
+
# whether there was, at any point in time, a pushy default.
|
102
|
+
#
|
103
|
+
# The whole handling of pushies can and will be improved in the future.
|
104
|
+
!@we_have_a_pushy
|
105
|
+
end
|
106
|
+
|
107
|
+
def we_have_a_pushy!
|
108
|
+
@we_have_a_pushy = true
|
109
|
+
puts "Just set pushy!. Did it work? #{we_have_a_pushy?}"
|
110
|
+
end
|
111
|
+
|
112
|
+
protected
|
113
|
+
|
114
|
+
def assign_formatter_to_logger
|
115
|
+
logger.formatter = proc do |severity, time, progname, msg|
|
116
|
+
"\nCUSHIONDEFAULTS: #{severity}\n\t\##{progname ? "#{progname} at" : "At"} #{time.strftime('%d %b %Y, %H:%M:%S%p')}\n\t#{msg}\n"
|
117
|
+
end
|
118
|
+
end
|
56
119
|
end
|
@@ -26,7 +26,12 @@ module CushionDefaults
|
|
26
26
|
# If +key+ is in +self+ and +y+, then the value of +y+ will replace that in +self+ in the resulting +Hash+.
|
27
27
|
# +y+ :: Hash (of any length) whose key/values will be added to this +DefaultsHash+.
|
28
28
|
def +(y)
|
29
|
-
y.each
|
29
|
+
y.each do |key, val|
|
30
|
+
if has_key? key
|
31
|
+
CushionDefaults.log("As #{@owner} already has the default #{key} defined, this call to + is overwriting it.", :info)
|
32
|
+
end
|
33
|
+
self[key] = val
|
34
|
+
end
|
30
35
|
self
|
31
36
|
end
|
32
37
|
|
@@ -62,6 +67,7 @@ module CushionDefaults
|
|
62
67
|
@pushy_defaults.delete(key)
|
63
68
|
@polite_defaults.delete(key)
|
64
69
|
super(key)
|
70
|
+
CushionDefaults.log("Default for #{key} in #{@owner} deleted.")
|
65
71
|
end
|
66
72
|
|
67
73
|
# Custom clear method. We need to check whether or not we should delete the methods associated with the keys, and we
|
@@ -73,6 +79,7 @@ module CushionDefaults
|
|
73
79
|
@pushy_defaults.clear
|
74
80
|
@polite_defaults.clear
|
75
81
|
super
|
82
|
+
CushionDefaults.log("All defaults cleared for #{@owner}.", :info)
|
76
83
|
end
|
77
84
|
|
78
85
|
# Custom clear method. We need to check whether or not we should delete the methods associated with the key.
|
@@ -112,13 +119,16 @@ module CushionDefaults
|
|
112
119
|
end
|
113
120
|
|
114
121
|
def pushy!(sym)
|
122
|
+
CushionDefaults.conf.we_have_a_pushy!
|
115
123
|
@pushy_defaults.add(sym)
|
116
124
|
@polite_defaults.delete(sym)
|
125
|
+
CushionDefaults.log(":#{sym} in #{@owner} is now pushy.")
|
117
126
|
end
|
118
127
|
|
119
128
|
def not_pushy!(sym)
|
120
129
|
@pushy_defaults.delete(sym)
|
121
130
|
@polite_defaults.add(sym)
|
131
|
+
CushionDefaults.log("#{sym} in #{@owner} is now polite.")
|
122
132
|
end
|
123
133
|
|
124
134
|
def pushy?(sym)
|
data/lib/cushion_defaults.rb
CHANGED
@@ -10,25 +10,14 @@ require 'cushion_defaults/defaults_hash'
|
|
10
10
|
# +Klass+.
|
11
11
|
module CushionDefaults
|
12
12
|
|
13
|
-
VERSION = '0.0
|
14
|
-
|
15
|
-
# CONFIG
|
13
|
+
VERSION = '0.1.0'
|
16
14
|
|
17
15
|
# Location CushionDefaults looks for (optional) config file
|
18
16
|
CALLING_PATH = File.expand_path(File.dirname($0)) + '/'
|
19
17
|
|
20
18
|
CONFIG_LOCATION = CALLING_PATH + 'config/cushion_defaults.yaml'
|
21
19
|
|
22
|
-
#
|
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.
|
20
|
+
# Create or return a cached (effectively singleton) +Configuration+ object.
|
32
21
|
def self.configuration
|
33
22
|
@configuration ||= Configuration.new
|
34
23
|
end
|
@@ -37,6 +26,44 @@ module CushionDefaults
|
|
37
26
|
self.configuration
|
38
27
|
end
|
39
28
|
|
29
|
+
def self.preliminary_setup
|
30
|
+
local_conf_path = CALLING_PATH + configuration.yaml_source_folder + 'cushion_defaults.yaml'
|
31
|
+
if File.exists?(CONFIG_LOCATION)
|
32
|
+
t = File.open(CONFIG_LOCATION)
|
33
|
+
log("Found and opened config file at #{CONFIG_LOCATION}", :info)
|
34
|
+
elsif File.exists?(local_conf_path)
|
35
|
+
t = File.open(local_conf_path)
|
36
|
+
log("Found and opened config file at #{local_conf_path}", :info)
|
37
|
+
else
|
38
|
+
t = nil
|
39
|
+
log("No config file found. Looked at #{CONFIG_LOCATION} and #{local_conf_path}.", :info)
|
40
|
+
end
|
41
|
+
|
42
|
+
conf.from_hash(YAML::load(t)) if t
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.log(str, level=:debug)
|
46
|
+
return unless conf.record_in_log
|
47
|
+
caller_method_name = caller_locations(1,1)[0].label.to_s
|
48
|
+
conf.logger.progname = caller_method_name
|
49
|
+
case level
|
50
|
+
when :debug
|
51
|
+
conf.logger.debug {str}
|
52
|
+
when :fatal
|
53
|
+
conf.logger.fatal {str}
|
54
|
+
when :error
|
55
|
+
conf.logger.error {str}
|
56
|
+
when :warn
|
57
|
+
conf.logger.warn {str}
|
58
|
+
when :info
|
59
|
+
conf.logger.info {str}
|
60
|
+
else
|
61
|
+
conf.logger.unknown {str}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
self.preliminary_setup
|
66
|
+
|
40
67
|
def self.nilish?(y)
|
41
68
|
if conf.ignore_attempts_to_set_nil
|
42
69
|
y.nil? || (conf.blank_str_is_nil && y.eql?(''))
|
@@ -48,36 +75,29 @@ module CushionDefaults
|
|
48
75
|
# Yield the configuration object to a block.
|
49
76
|
#
|
50
77
|
# The following configuration methods are available with the returned object:
|
51
|
-
# - #
|
52
|
-
# - #
|
78
|
+
# - #update_readers (boolean) :: If true, cushion_readers will be added/removed automatically as defaults are added/removed. Def: false.
|
79
|
+
# - #update_writers (boolean) :: If true, cushion_writers will be added/removed automatically as defaults are added/removed. Def: false.
|
53
80
|
# - #auto_load_from_yaml (boolean) :: Specifies whether we should attempt to automatically load defaults from class-specific yaml files. Def: true.
|
54
81
|
# - #yaml_source_folder (string) :: Specifies the folder that contains class-specific yaml files. Def: 'config/cushion_defaults/'.
|
55
82
|
# - #yaml_source_full_path (string) :: Specifies the full path for class-specific yaml files. Def: +nil+.
|
83
|
+
# - #record_in_log (boolean) :: If true, module will write to config.logger as appropriate. Def: true.
|
84
|
+
# - #logger (Logger) :: Any object that responds to logging methods. Def: Logger.new
|
56
85
|
# - #whiny_yaml (boolean) :: If true, a warning will be issued if a class-specific yaml file cannot be found. Def: false.
|
57
86
|
# - #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
87
|
# - #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
88
|
# - #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
89
|
def self.configure
|
62
90
|
yield(configuration)
|
63
91
|
end
|
64
92
|
|
65
|
-
if File.exists?(CONFIG_LOCATION)
|
66
|
-
t = File.open(CONFIG_LOCATION)
|
67
|
-
elsif File.exists?(CALLING_PATH + configuration.yaml_source_folder + 'cushion_defaults.yaml')
|
68
|
-
t = File.open(CALLING_PATH + configuration.yaml_source_folder + 'cushion_defaults.yaml')
|
69
|
-
else
|
70
|
-
t = nil
|
71
|
-
end
|
72
|
-
|
73
|
-
conf.from_hash(YAML::load(t)) if t
|
74
|
-
|
75
93
|
# Add class methods and set up +DefaultsHash+ when the module is included in a class.
|
76
94
|
#
|
77
95
|
# If +AUTO_LOAD_FROM_YAML+, then it also searches for a yaml configuration file for the class in the path specified
|
78
96
|
# in the config variables.
|
79
97
|
def self.included(base)
|
80
98
|
|
99
|
+
log("CushionDefaults has been included in #{base}.")
|
100
|
+
|
81
101
|
base.extend(ClassMethods)
|
82
102
|
|
83
103
|
if configuration.auto_load_from_yaml
|
@@ -115,6 +135,8 @@ module CushionDefaults
|
|
115
135
|
if !has_specified? key || (act_if_nilish && CushionDefaults.nilish?(instance_variable_get("@#{key}")))
|
116
136
|
default_value = default(key)
|
117
137
|
instance_variable_set("@#{key}", default_value)
|
138
|
+
else
|
139
|
+
log("Did not update #{key}")
|
118
140
|
end
|
119
141
|
end
|
120
142
|
end
|