@@ -10,6 +10,16 @@ def name # :nodoc:
10
10
instance . key? ( "name" ) ? instance . name : super
11
11
end
12
12
13
+ # Enables Settings.get('nested.key.name') for dynamic access
14
+ def get ( key )
15
+ parts = key . split ( '.' )
16
+ curs = self
17
+ while p = parts . shift
18
+ curs = curs . send ( p )
19
+ end
20
+ curs
21
+ end
22
+
13
23
def source ( value = nil )
14
24
if value . nil?
15
25
@source
@@ -27,13 +37,15 @@ def namespace(value = nil)
27
37
end
28
38
29
39
def []( key )
30
- # Setting.key.value or Setting [:key][:value ] or Setting['key']['value ']
31
- fetch ( key . to_s , nil )
40
+ # Setting[:key][:key2 ] or Setting['key']['key2 ']
41
+ instance . fetch ( key . to_s , nil )
32
42
end
33
43
34
- def []=( key , val )
35
- # Setting[:key] = 'value' for dynamic settings
36
- store ( key . to_s , val )
44
+ def []=( key , val )
45
+ # Setting[:key][:key2] = 'value' for dynamic settings
46
+ val = self . class . new ( val , source ) if val . is_a? Hash
47
+ instance . store ( key . to_s , val )
48
+ instance . create_accessor_for ( key . to_s , val )
37
49
end
38
50
39
51
def load!
@@ -75,39 +87,57 @@ def initialize(hash_or_file = self.class.source, section = nil)
75
87
hash = hash [ self . class . namespace ] if self . class . namespace
76
88
self . replace hash
77
89
end
78
- @section = section || hash_or_file # so end of error says "in application.yml"
90
+ @section = section || self . class . source # so end of error says "in application.yml"
79
91
create_accessors!
80
92
end
81
93
82
94
# Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used.
83
95
# Otherwise, create_accessors! (called by new) will have created actual methods for each key.
84
- def method_missing ( key , *args , &block )
85
- begin
86
- value = fetch ( key . to_s )
87
- rescue IndexError
88
- raise MissingSetting , "Missing setting '#{ key } ' in #{ @section } "
89
- end
96
+ def method_missing ( name , *args , &block )
97
+ key = name . to_s
98
+ raise MissingSetting , "Missing setting '#{ key } ' in #{ @section } " unless has_key? key
99
+ value = fetch ( key )
100
+ create_accessor_for ( key )
90
101
value . is_a? ( Hash ) ? self . class . new ( value , "'#{ key } ' section in #{ @section } " ) : value
91
102
end
92
103
104
+ def []( key )
105
+ # Setting[:key][:key2] or Setting['key']['key2']
106
+ fetch ( key . to_s , nil )
107
+ end
108
+
109
+ def []=( key , val )
110
+ # Setting[:key][:key2] = 'value' for dynamic settings
111
+ val = self . class . new ( val , @section ) if val . is_a? Hash
112
+ store ( key . to_s , val )
113
+ create_accessor_for ( key . to_s , val )
114
+ end
115
+
93
116
private
94
117
# This handles naming collisions with Sinatra/Vlad/Capistrano. Since these use a set()
95
118
# helper that defines methods in Object, ANY method_missing ANYWHERE picks up the Vlad/Sinatra
96
119
# settings! So settings.deploy_to title actually calls Object.deploy_to (from set :deploy_to, "host"),
97
120
# rather than the app_yml['deploy_to'] hash. Jeezus.
98
121
def create_accessors!
99
122
self . each do |key , val |
100
- # Use instance_eval/class_eval because they're actually more efficient than define_method{}
101
- # http://stackoverflow.com/questions/185947/ruby-definemethod-vs-def
102
- # http://bmorearty.wordpress.com/2009/01/09/fun-with-rubys-instance_eval-and-class_eval/
103
- self . class . class_eval <<-EndEval
104
- def #{ key }
105
- return @#{ key } if @#{ key } # cache (performance)
106
- value = fetch('#{ key } ')
107
- @#{ key } = value.is_a?(Hash) ? self.class.new(value, "'#{ key } ' section in #{ @section } ") : value
108
- end
109
- EndEval
123
+ create_accessor_for ( key )
110
124
end
111
125
end
112
126
127
+ # Use instance_eval/class_eval because they're actually more efficient than define_method{}
128
+ # http://stackoverflow.com/questions/185947/ruby-definemethod-vs-def
129
+ # http://bmorearty.wordpress.com/2009/01/09/fun-with-rubys-instance_eval-and-class_eval/
130
+ def create_accessor_for ( key , val = nil )
131
+ return unless key . to_s =~ /^\w +$/ # could have "some-setting:" which blows up class_eval
132
+ instance_variable_set ( "@#{ key } " , val )
133
+ self . class . class_eval <<-EndEval
134
+ def #{ key }
135
+ return @#{ key } if @#{ key }
136
+ raise MissingSetting, "Missing setting '#{ key } ' in #{ @section } " unless has_key? '#{ key } '
137
+ value = fetch('#{ key } ')
138
+ @#{ key } = value.is_a?(Hash) ? self.class.new(value, "'#{ key } ' section in #{ @section } ") : value
139
+ end
140
+ EndEval
141
+ end
142
+
113
143
end
0 commit comments