fun_with_configurations 0.0.1 → 0.0.2
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 +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:
|