cushion_defaults 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|