settingslogic 2.0.5 → 2.0.6
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.
- data/VERSION.yml +1 -1
- data/lib/settingslogic.rb +80 -34
- data/settingslogic.gemspec +2 -2
- data/spec/settings.rb +3 -0
- data/spec/settings.yml +4 -1
- data/spec/settingslogic_spec.rb +56 -4
- data/spec/spec_helper.rb +1 -1
- metadata +2 -2
data/VERSION.yml
CHANGED
data/lib/settingslogic.rb
CHANGED
@@ -4,12 +4,22 @@ require "erb"
|
|
4
4
|
# A simple settings solution using a YAML file. See README for more information.
|
5
5
|
class Settingslogic < Hash
|
6
6
|
class MissingSetting < StandardError; end
|
7
|
-
|
7
|
+
|
8
8
|
class << self
|
9
9
|
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,15 +37,16 @@ class Settingslogic < Hash
|
|
27
37
|
end
|
28
38
|
|
29
39
|
def [](key)
|
30
|
-
|
31
|
-
fetch(key.to_s,nil)
|
40
|
+
instance.fetch(key.to_s, nil)
|
32
41
|
end
|
33
42
|
|
34
|
-
def []=(key,val)
|
35
|
-
# Setting[:key] = 'value' for dynamic settings
|
36
|
-
|
43
|
+
def []=(key, val)
|
44
|
+
# Setting[:key][:key2] = 'value' for dynamic settings
|
45
|
+
val = new(val, source) if val.is_a? Hash
|
46
|
+
instance.store(key.to_s, val)
|
47
|
+
instance.create_accessor_for(key, val)
|
37
48
|
end
|
38
|
-
|
49
|
+
|
39
50
|
def load!
|
40
51
|
instance
|
41
52
|
true
|
@@ -48,12 +59,29 @@ class Settingslogic < Hash
|
|
48
59
|
|
49
60
|
private
|
50
61
|
def instance
|
51
|
-
@instance
|
62
|
+
return @instance if @instance
|
63
|
+
@instance = new
|
64
|
+
create_accessors!
|
65
|
+
@instance
|
52
66
|
end
|
53
67
|
|
54
68
|
def method_missing(name, *args, &block)
|
55
69
|
instance.send(name, *args, &block)
|
56
70
|
end
|
71
|
+
|
72
|
+
# It would be great to DRY this up somehow, someday, but it's difficult because
|
73
|
+
# of the singleton pattern. Basically this proxies Setting.foo to Setting.instance.foo
|
74
|
+
def create_accessors!
|
75
|
+
instance.each do |key,val|
|
76
|
+
create_accessor_for(key)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_accessor_for(key)
|
81
|
+
return unless key.to_s =~ /^\w+$/ # could have "some-setting:" which blows up eval
|
82
|
+
instance_eval "def #{key}; instance.send(:#{key}); end"
|
83
|
+
end
|
84
|
+
|
57
85
|
end
|
58
86
|
|
59
87
|
# Initializes a new settings object. You can initialize an object in any of the following ways:
|
@@ -67,7 +95,10 @@ class Settingslogic < Hash
|
|
67
95
|
# if you are using this in rails. If you pass a string it should be an absolute path to your settings file.
|
68
96
|
# Then you can pass a hash, and it just allows you to access the hash via methods.
|
69
97
|
def initialize(hash_or_file = self.class.source, section = nil)
|
98
|
+
#puts "new! #{hash_or_file}"
|
70
99
|
case hash_or_file
|
100
|
+
when nil
|
101
|
+
raise Errno::ENOENT, "No file specified as Settingslogic source"
|
71
102
|
when Hash
|
72
103
|
self.replace hash_or_file
|
73
104
|
else
|
@@ -75,39 +106,54 @@ class Settingslogic < Hash
|
|
75
106
|
hash = hash[self.class.namespace] if self.class.namespace
|
76
107
|
self.replace hash
|
77
108
|
end
|
78
|
-
@section = section ||
|
109
|
+
@section = section || self.class.source # so end of error says "in application.yml"
|
79
110
|
create_accessors!
|
80
111
|
end
|
81
112
|
|
82
113
|
# Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used.
|
83
114
|
# Otherwise, create_accessors! (called by new) will have created actual methods for each key.
|
84
|
-
def method_missing(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
115
|
+
def method_missing(name, *args, &block)
|
116
|
+
key = name.to_s
|
117
|
+
raise MissingSetting, "Missing setting '#{key}' in #{@section}" unless has_key? key
|
118
|
+
value = fetch(key)
|
119
|
+
create_accessor_for(key)
|
90
120
|
value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value
|
91
121
|
end
|
92
122
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
123
|
+
def [](key)
|
124
|
+
fetch(key.to_s, nil)
|
125
|
+
end
|
126
|
+
|
127
|
+
def []=(key,val)
|
128
|
+
# Setting[:key][:key2] = 'value' for dynamic settings
|
129
|
+
val = self.class.new(val, @section) if val.is_a? Hash
|
130
|
+
store(key.to_s, val)
|
131
|
+
create_accessor_for(key, val)
|
132
|
+
end
|
133
|
+
|
134
|
+
# This handles naming collisions with Sinatra/Vlad/Capistrano. Since these use a set()
|
135
|
+
# helper that defines methods in Object, ANY method_missing ANYWHERE picks up the Vlad/Sinatra
|
136
|
+
# settings! So settings.deploy_to title actually calls Object.deploy_to (from set :deploy_to, "host"),
|
137
|
+
# rather than the app_yml['deploy_to'] hash. Jeezus.
|
138
|
+
def create_accessors!
|
139
|
+
self.each do |key,val|
|
140
|
+
create_accessor_for(key)
|
111
141
|
end
|
142
|
+
end
|
112
143
|
|
144
|
+
# Use instance_eval/class_eval because they're actually more efficient than define_method{}
|
145
|
+
# http://stackoverflow.com/questions/185947/ruby-definemethod-vs-def
|
146
|
+
# http://bmorearty.wordpress.com/2009/01/09/fun-with-rubys-instance_eval-and-class_eval/
|
147
|
+
def create_accessor_for(key, val=nil)
|
148
|
+
return unless key.to_s =~ /^\w+$/ # could have "some-setting:" which blows up eval
|
149
|
+
instance_variable_set("@#{key}", val) if val
|
150
|
+
self.class.class_eval <<-EndEval
|
151
|
+
def #{key}
|
152
|
+
return @#{key} if @#{key}
|
153
|
+
raise MissingSetting, "Missing setting '#{key}' in #{@section}" unless has_key? '#{key}'
|
154
|
+
value = fetch('#{key}')
|
155
|
+
@#{key} = value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value
|
156
|
+
end
|
157
|
+
EndEval
|
158
|
+
end
|
113
159
|
end
|
data/settingslogic.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{settingslogic}
|
8
|
-
s.version = "2.0.
|
8
|
+
s.version = "2.0.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ben Johnson of Binary Logic"]
|
12
|
-
s.date = %q{2010-02-
|
12
|
+
s.date = %q{2010-02-12}
|
13
13
|
s.email = %q{bjohnson@binarylogic.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
data/spec/settings.rb
CHANGED
data/spec/settings.yml
CHANGED
data/spec/settingslogic_spec.rb
CHANGED
@@ -20,7 +20,7 @@ describe "Settingslogic" do
|
|
20
20
|
it "should enable erb" do
|
21
21
|
Settings.setting3.should == 25
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
it "should namespace settings" do
|
25
25
|
Settings2.setting1_child.should == "saweet"
|
26
26
|
Settings2.deep.another.should == "my value"
|
@@ -37,9 +37,13 @@ describe "Settingslogic" do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
it "should not collide with global methods" do
|
40
|
+
Settings3.nested.collides.does.should == 'not either'
|
41
|
+
Settings3[:nested] = 'fooey'
|
42
|
+
Settings3[:nested].should == 'fooey'
|
43
|
+
Settings3.nested.should == 'fooey'
|
40
44
|
Settings3.collides.does.should == 'not'
|
41
45
|
end
|
42
|
-
|
46
|
+
|
43
47
|
it "should raise a helpful error message" do
|
44
48
|
e = nil
|
45
49
|
begin
|
@@ -49,7 +53,7 @@ describe "Settingslogic" do
|
|
49
53
|
end
|
50
54
|
e.should_not be_nil
|
51
55
|
e.message.should =~ /Missing setting 'missing' in/
|
52
|
-
|
56
|
+
|
53
57
|
e = nil
|
54
58
|
begin
|
55
59
|
Settings.language.missing
|
@@ -71,14 +75,62 @@ describe "Settingslogic" do
|
|
71
75
|
e.message.should =~ /Missing setting 'erlang' in 'language' section/
|
72
76
|
|
73
77
|
Settings.language['erlang'].should be_nil
|
74
|
-
Settings.language['erlang']
|
78
|
+
Settings.language['erlang'] = 5
|
75
79
|
Settings.language['erlang'].should == 5
|
76
80
|
|
77
81
|
Settings.language['erlang'] = {'paradigm' => 'functional'}
|
78
82
|
Settings.language.erlang.paradigm.should == 'functional'
|
83
|
+
Settings.respond_to?('erlang').should be_false
|
79
84
|
|
80
85
|
Settings.reload!
|
81
86
|
Settings.language['erlang'].should be_nil
|
87
|
+
|
88
|
+
Settings.language[:erlang] ||= 5
|
89
|
+
Settings.language[:erlang].should == 5
|
90
|
+
|
91
|
+
Settings.language[:erlang] = {}
|
92
|
+
Settings.language[:erlang][:paradigm] = 'functional'
|
93
|
+
Settings.language.erlang.paradigm.should == 'functional'
|
94
|
+
|
95
|
+
Settings[:toplevel] = '42'
|
96
|
+
Settings.toplevel.should == '42'
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should raise an error on a nil source argument" do
|
100
|
+
class NoSource < Settingslogic; end
|
101
|
+
e = nil
|
102
|
+
begin
|
103
|
+
NoSource.foo.bar
|
104
|
+
rescue => e
|
105
|
+
e.should be_kind_of Errno::ENOENT
|
106
|
+
end
|
107
|
+
e.should_not be_nil
|
108
|
+
end
|
109
|
+
|
110
|
+
# This one edge case currently does not pass, because it requires very
|
111
|
+
# esoteric code in order to make it pass. It was judged not worth fixing,
|
112
|
+
# as it introduces significant complexity for minor gain.
|
113
|
+
# it "should handle reloading top-level settings"
|
114
|
+
# Settings[:inspect] = 'yeah baby'
|
115
|
+
# Settings.inspect.should == 'yeah baby'
|
116
|
+
# Settings.reload!
|
117
|
+
# Settings.inspect.should == 'Settings'
|
118
|
+
# end
|
119
|
+
|
120
|
+
it "should handle oddly-named settings" do
|
121
|
+
Settings.language['some-dash-setting#'] = 'dashtastic'
|
122
|
+
Settings.language['some-dash-setting#'].should == 'dashtastic'
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should support instance usage as well" do
|
126
|
+
settings = SettingsInst.new(Settings.source)
|
127
|
+
settings.setting1.setting1_child.should == "saweet"
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should be able to get() a key with dot.notation" do
|
131
|
+
Settings.get('setting1.setting1_child').should == "saweet"
|
132
|
+
Settings.get('setting1.deep.another').should == "my value"
|
133
|
+
Settings.get('setting1.deep.child.value').should == 2
|
82
134
|
end
|
83
135
|
|
84
136
|
# Put this test last or else call to .instance will load @instance,
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: settingslogic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Johnson of Binary Logic
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-12 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|