fun_with_configurations 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/fun_with/configurations/config.rb +87 -7
- data/lib/fun_with/configurations/object.rb +9 -1
- data/lib/fun_with/configurations/try_object.rb +65 -0
- data/lib/fun_with_configurations.rb +8 -0
- data/test/data/config.yml +12 -0
- data/test/test_fun_with_configurations.rb +103 -4
- metadata +5 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
@@ -3,8 +3,34 @@ module FunWith
|
|
3
3
|
class KeyError < Exception
|
4
4
|
end
|
5
5
|
|
6
|
-
class
|
7
|
-
|
6
|
+
class ChainError < Exception
|
7
|
+
end
|
8
|
+
|
9
|
+
module ConfigOverriddenMethods
|
10
|
+
def self.override_method( sym )
|
11
|
+
eval <<-EOS
|
12
|
+
def #{sym}( *args, &block )
|
13
|
+
self.method_missing(:sym, *args, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def #{sym}=( *args, &block )
|
17
|
+
self.method_missing( :#{sym}, *args, &block )
|
18
|
+
end
|
19
|
+
EOS
|
20
|
+
end
|
21
|
+
|
22
|
+
for sym in [:test]
|
23
|
+
override_method( sym )
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Config
|
28
|
+
include ConfigOverriddenMethods
|
29
|
+
|
30
|
+
def initialize( key_to_self = nil, parent = nil, &block )
|
31
|
+
@key_to_self = key_to_self
|
32
|
+
@parent = parent
|
33
|
+
@config_vars = {}
|
8
34
|
self.instance_exec( &block ) if block_given?
|
9
35
|
end
|
10
36
|
|
@@ -12,10 +38,12 @@ module FunWith
|
|
12
38
|
method = method.to_s.gsub( /=$/, '' ).to_sym
|
13
39
|
|
14
40
|
if block_given?
|
15
|
-
self[method] = Config.new unless self[method].is_a?(Config)
|
41
|
+
self[method] = Config.new(method, self) unless self[method].is_a?(Config)
|
16
42
|
self[method].instance_exec( &block )
|
17
|
-
elsif args.length
|
43
|
+
elsif args.length == 1
|
18
44
|
self[method] = args.first
|
45
|
+
elsif args.length > 1
|
46
|
+
self[method] = args
|
19
47
|
else
|
20
48
|
self[method]
|
21
49
|
end
|
@@ -24,20 +52,72 @@ module FunWith
|
|
24
52
|
def []( sym )
|
25
53
|
sym = sym.to_sym if sym.is_a?(String)
|
26
54
|
self.class.key_check( sym )
|
27
|
-
|
55
|
+
@config_vars[ sym ]
|
28
56
|
end
|
29
57
|
|
30
58
|
def []=( sym, val )
|
31
59
|
sym = sym.to_sym if sym.is_a?(String)
|
32
60
|
self.class.key_check( sym )
|
33
|
-
|
61
|
+
@config_vars[ sym ] = val
|
62
|
+
end
|
63
|
+
|
64
|
+
# Say you had a configuration that had multiple entries, and you wanted to select from
|
65
|
+
# among them at runtime. Example:
|
66
|
+
# config:
|
67
|
+
# important_folder:
|
68
|
+
# development: "/this/directory",
|
69
|
+
# test: "/that/directory",
|
70
|
+
# production: "~/another/directory"
|
71
|
+
#
|
72
|
+
# You could do config.important_folder[environment] every time you want to access that setting.
|
73
|
+
# Or you can do config.important_folder.promote_configuration(:development) and have the
|
74
|
+
# development subconfiguration replace the important_folder: configuration
|
75
|
+
#
|
76
|
+
# You can promote a sub-sub-sub-config by sending an array of symbols. But I hope it
|
77
|
+
# never comes to that.
|
78
|
+
def promote_configuration( *keys )
|
79
|
+
replace_with = self.try.config_method_chain_result( keys )
|
80
|
+
if replace_with.success?
|
81
|
+
@parent[@key_to_self] = replace_with.config
|
82
|
+
else
|
83
|
+
raise ChainError.new( "config failed to promote_configuration #{keys.inspect}" )
|
84
|
+
end
|
34
85
|
end
|
35
86
|
|
36
87
|
def self.key_check( sym )
|
37
|
-
@reserved_symbols ||=
|
88
|
+
@reserved_symbols ||= Config.instance_methods - self.fwc_overridden_methods
|
89
|
+
|
38
90
|
raise KeyError.new("#{sym} is not a symbol") unless sym.is_a?(Symbol)
|
39
91
|
raise KeyError.new("#{sym} is reserved for use by Hash") if @reserved_symbols.include?( sym )
|
40
92
|
end
|
93
|
+
|
94
|
+
def try( *keys )
|
95
|
+
t = TryObject.new( self )
|
96
|
+
|
97
|
+
for key in keys
|
98
|
+
t[key]
|
99
|
+
end
|
100
|
+
|
101
|
+
t
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.from_hash( hash )
|
105
|
+
config = self.new
|
106
|
+
|
107
|
+
for k, v in hash
|
108
|
+
config.send( k, v.is_a?( Hash ) ? self.from_hash( v ) : v )
|
109
|
+
end
|
110
|
+
|
111
|
+
config
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.fwc_overridden_methods
|
115
|
+
ConfigOverriddenMethods.instance_methods.grep( /[^=]$/ )
|
116
|
+
end
|
117
|
+
|
118
|
+
def fwc_overridden_methods
|
119
|
+
self.class.fwc_overridden_methods
|
120
|
+
end
|
41
121
|
end
|
42
122
|
end
|
43
123
|
end
|
@@ -1,11 +1,19 @@
|
|
1
1
|
class Object
|
2
2
|
def install_fwc_config( config = nil, &block )
|
3
3
|
extend FunWith::Configurations::Configurable
|
4
|
-
self.config = config || FunWith::Configurations::Config.new( &block )
|
4
|
+
self.config = config || FunWith::Configurations::Config.new( nil, &block )
|
5
5
|
self.config
|
6
6
|
end
|
7
7
|
|
8
8
|
def install_fwc_config_from_file( filename )
|
9
9
|
install_fwc_config( eval( File.read( filename ) ) ) # TODO: Has to be a better way than eval(). Dangerous.
|
10
10
|
end
|
11
|
+
|
12
|
+
def install_fwc_config_from_hash( hash )
|
13
|
+
install_fwc_config( FunWith::Configurations::Config.from_hash( hash ) )
|
14
|
+
end
|
15
|
+
|
16
|
+
def install_fwc_config_from_yaml( yaml_string )
|
17
|
+
install_fwc_config_from_hash( YAML.load( yaml_string ) )
|
18
|
+
end
|
11
19
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Configurations
|
3
|
+
class TryResult
|
4
|
+
attr_accessor :config
|
5
|
+
def initialize( config, success )
|
6
|
+
@config = config
|
7
|
+
@success = success
|
8
|
+
end
|
9
|
+
|
10
|
+
def success?
|
11
|
+
@success
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class TryObject
|
16
|
+
# takes a Config object
|
17
|
+
def initialize( config )
|
18
|
+
@config = config
|
19
|
+
@success = true
|
20
|
+
@leaf = false
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing( method, *args )
|
24
|
+
follow_config_method_chain( method )
|
25
|
+
end
|
26
|
+
|
27
|
+
def [] method_key
|
28
|
+
follow_config_method_chain( method_key.to_sym )
|
29
|
+
end
|
30
|
+
|
31
|
+
def follow_config_method_chain( method )
|
32
|
+
if @success == true
|
33
|
+
if @config.is_a?(Config) && @config.has_key?(method)
|
34
|
+
@config = @config[method]
|
35
|
+
unless @config.is_a?(Config)
|
36
|
+
@leaf = true
|
37
|
+
end
|
38
|
+
elsif @leaf
|
39
|
+
@leaf = false # declare unsuccessful on next call.
|
40
|
+
else
|
41
|
+
@success = false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def config_method_chain_result( *keys )
|
49
|
+
keys = keys.flatten
|
50
|
+
|
51
|
+
if success?
|
52
|
+
keys.each do |k|
|
53
|
+
follow_config_method_chain(k)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
TryResult.new( @config, success? )
|
58
|
+
end
|
59
|
+
|
60
|
+
def success?
|
61
|
+
@success
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -1,5 +1,13 @@
|
|
1
1
|
require 'fun_with_files'
|
2
|
+
module FunWith
|
3
|
+
module Configurations
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
FunWith::Files::RootPath.rootify( FunWith::Configurations, __FILE__.fwf_filepath.dirname.up )
|
8
|
+
|
2
9
|
require_relative File.join( "fun_with", "configurations", "config" )
|
3
10
|
require_relative File.join( "fun_with", "configurations", "configurations" )
|
4
11
|
require_relative File.join( "fun_with", "configurations", "object" )
|
12
|
+
require_relative File.join( "fun_with", "configurations", "try_object" )
|
5
13
|
|
@@ -25,6 +25,16 @@ class TestFunWithConfigurations < Test::Unit::TestCase
|
|
25
25
|
e :f
|
26
26
|
f :g
|
27
27
|
end
|
28
|
+
|
29
|
+
s do
|
30
|
+
t do
|
31
|
+
u do
|
32
|
+
v do
|
33
|
+
w :x
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
28
38
|
end
|
29
39
|
end
|
30
40
|
|
@@ -66,29 +76,118 @@ class TestFunWithConfigurations < Test::Unit::TestCase
|
|
66
76
|
assert_equal nil, @obj.config[:c=]
|
67
77
|
end
|
68
78
|
|
69
|
-
should "gripe when given a
|
79
|
+
should "gripe when given a hash" do
|
70
80
|
assert defined?( FunWith::Configurations::KeyError )
|
71
81
|
assert_raises FunWith::Configurations::KeyError do |err|
|
72
|
-
@obj.config[
|
82
|
+
@obj.config[{c: "hey"}]
|
73
83
|
end
|
74
84
|
end
|
75
85
|
|
76
86
|
should "gripe when given a reserved method as a key" do
|
77
87
|
assert defined?( FunWith::Configurations::KeyError )
|
78
88
|
assert_raises FunWith::Configurations::KeyError do |err|
|
79
|
-
@obj.config[:
|
89
|
+
@obj.config[:clone] = ["22461", "80129"]
|
90
|
+
end
|
91
|
+
|
92
|
+
assert_raises FunWith::Configurations::KeyError do |err|
|
93
|
+
@obj.config.clone = ["22461", "80129"]
|
80
94
|
end
|
81
95
|
end
|
96
|
+
|
97
|
+
should "pass tests for try() function" do
|
98
|
+
assert_equal true, @obj.config.try.a.success?
|
99
|
+
assert_equal true, @obj.config.try.a.b.success?
|
100
|
+
assert_equal false, @obj.config.try.a.b.c.success?
|
101
|
+
assert_equal false, @obj.config.try.a.b.c.d.e.f.g.h.success?
|
102
|
+
assert_equal true, @obj.config.try.c.d.success?
|
103
|
+
assert_equal true, @obj.config.try[:c]["d"].success? # alternate traversal mechanism
|
104
|
+
end
|
105
|
+
|
106
|
+
should "have parents" do
|
107
|
+
assert_kind_of FunWith::Configurations::Config, @obj.config.c.instance_variable_get(:@parent)
|
108
|
+
assert_kind_of FunWith::Configurations::Config, @obj.config.s.t.u.instance_variable_get(:@parent).instance_variable_get(:@parent)
|
109
|
+
end
|
110
|
+
|
111
|
+
should "promote subconfiguration" do
|
112
|
+
assert_equal :x, @obj.config.s.t.u.v.w
|
113
|
+
@obj.config.s.t.u.v.promote_configuration(:w)
|
114
|
+
assert_equal :x, @obj.config.s.t.u.v
|
115
|
+
end
|
116
|
+
|
117
|
+
should "promote sub-subconfiguration" do
|
118
|
+
assert_equal :x, @obj.config.s.t.u.v.w
|
119
|
+
@obj.config.s.t.u.promote_configuration(:v,:w)
|
120
|
+
assert_equal :x, @obj.config.s.t.u
|
121
|
+
end
|
82
122
|
end
|
83
123
|
|
84
124
|
should "successfully create configuration manually" do
|
85
125
|
@obj = Object.new
|
86
126
|
@obj.extend( FunWith::Configurations::Configurable )
|
87
|
-
@obj.config = FunWith::Configurations::Config.new do
|
127
|
+
@obj.config = FunWith::Configurations::Config.new( nil ) do
|
88
128
|
betelgeuse "red"
|
89
129
|
rigel "blue-white"
|
90
130
|
end
|
91
131
|
|
92
132
|
assert_equal "blue-white", @obj.config.rigel
|
93
133
|
end
|
134
|
+
|
135
|
+
context "testing overridden methods|" do
|
136
|
+
setup do
|
137
|
+
@obj = Object.new
|
138
|
+
@obj.install_fwc_config do
|
139
|
+
malaprop :sym
|
140
|
+
blocky do
|
141
|
+
fish :guts
|
142
|
+
test :has_caused_problems
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
should "override test" do
|
148
|
+
assert @obj.config.blocky.respond_to?(:test)
|
149
|
+
assert_equal :has_caused_problems, @obj.config.blocky.test
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
should "hold multiple arguments as arrays" do
|
154
|
+
@obj = Object.new
|
155
|
+
@obj.install_fwc_config do
|
156
|
+
my_array 1,2,3,nil,5
|
157
|
+
my_array2 [1,2,3,nil,5]
|
158
|
+
end
|
159
|
+
|
160
|
+
assert_equal @obj.config.my_array, @obj.config.my_array2
|
161
|
+
end
|
162
|
+
|
163
|
+
context "testing from_hash" do
|
164
|
+
setup do
|
165
|
+
@obj = Object.new
|
166
|
+
@obj.install_fwc_config_from_hash({
|
167
|
+
:calista => "Flockhart",
|
168
|
+
:jude => "Law"
|
169
|
+
})
|
170
|
+
|
171
|
+
@obj2 = Object.new
|
172
|
+
@obj2.install_fwc_config_from_hash({
|
173
|
+
:a => {
|
174
|
+
:b => {
|
175
|
+
:c => {
|
176
|
+
:d => "e"
|
177
|
+
}
|
178
|
+
}
|
179
|
+
}
|
180
|
+
})
|
181
|
+
|
182
|
+
@obj3 = Object.new
|
183
|
+
yaml = FunWith::Configurations.root("test", "data", "config.yml").read
|
184
|
+
@obj3.install_fwc_config_from_yaml( yaml )
|
185
|
+
end
|
186
|
+
|
187
|
+
should "have successfully created configs" do
|
188
|
+
assert_equal "Law", @obj.config.jude
|
189
|
+
assert_equal "e", @obj2.config.a.b.c.d
|
190
|
+
assert_equal "definitely", @obj3.config.servers.puppymonster.services.oauth
|
191
|
+
end
|
192
|
+
end
|
94
193
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fun_with_configurations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fun_with_files
|
@@ -119,7 +119,9 @@ files:
|
|
119
119
|
- ./lib/fun_with/configurations/config.rb
|
120
120
|
- ./lib/fun_with/configurations/configurations.rb
|
121
121
|
- ./lib/fun_with/configurations/object.rb
|
122
|
+
- ./lib/fun_with/configurations/try_object.rb
|
122
123
|
- ./lib/fun_with_configurations.rb
|
124
|
+
- ./test/data/config.yml
|
123
125
|
- ./test/helper.rb
|
124
126
|
- ./test/test_fun_with_configurations.rb
|
125
127
|
- Gemfile
|
@@ -142,7 +144,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
142
144
|
version: '0'
|
143
145
|
segments:
|
144
146
|
- 0
|
145
|
-
hash:
|
147
|
+
hash: 4158279720265668030
|
146
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
149
|
none: false
|
148
150
|
requirements:
|