ahoward-configuration 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +186 -0
- data/README.erb +69 -0
- data/Rakefile +241 -0
- data/config/a.rb +5 -0
- data/config/b.rb +19 -0
- data/config/c.rb +8 -0
- data/config/d.rb +5 -0
- data/config/e.rb +13 -0
- data/configuration.gemspec +28 -0
- data/lib/configuration.rb +176 -0
- data/samples/a.rb +11 -0
- data/samples/b.rb +11 -0
- data/samples/c.rb +11 -0
- data/samples/d.rb +14 -0
- data/samples/e.rb +12 -0
- metadata +71 -0
data/README
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
NAME
|
2
|
+
configuration.rb
|
3
|
+
|
4
|
+
SYNOPSIS
|
5
|
+
pure ruby scoped configuration files
|
6
|
+
|
7
|
+
DESCRIPTION
|
8
|
+
configuration.rb provides a mechanism for configuring ruby programs with
|
9
|
+
ruby configuration files. a configuration.rb file, for example
|
10
|
+
'config/app.rb', can be written simply as
|
11
|
+
|
12
|
+
Configuration.for('app'){
|
13
|
+
key 'value'
|
14
|
+
foo 'bar'
|
15
|
+
port 42
|
16
|
+
}
|
17
|
+
|
18
|
+
and loaded via the normal ruby require/load mechanism
|
19
|
+
|
20
|
+
Kernel.load 'config/app.rb'
|
21
|
+
|
22
|
+
or with a slightly augmented loading mechnanism which simply searches an
|
23
|
+
extra set of paths in *addition* to the standard ones
|
24
|
+
|
25
|
+
Configuration.path = %w( config configuration )
|
26
|
+
|
27
|
+
Configuration.load 'app'
|
28
|
+
|
29
|
+
configurations are completely open
|
30
|
+
|
31
|
+
Configuration.for('app'){
|
32
|
+
object_id 'very open'
|
33
|
+
}
|
34
|
+
|
35
|
+
support arbitrarily nested values
|
36
|
+
|
37
|
+
Configuration.for('app'){
|
38
|
+
a { b { c { d 42 } } }
|
39
|
+
}
|
40
|
+
|
41
|
+
c = Configuration.for 'app'
|
42
|
+
|
43
|
+
p c.a.b.c.d #=> 42
|
44
|
+
|
45
|
+
allow POLS scoped lookup of vars
|
46
|
+
|
47
|
+
Configuration.for('config'){
|
48
|
+
outer 'bar'
|
49
|
+
|
50
|
+
inner {
|
51
|
+
value 42
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
c = Configuration.for 'config'
|
56
|
+
|
57
|
+
p c.outer #=> 'bar'
|
58
|
+
p c.inner.value #=> 42
|
59
|
+
p c.inner.outer #=> 'bar'
|
60
|
+
|
61
|
+
|
62
|
+
and not a whole lot else - configuration.rb is s very small library
|
63
|
+
consisting of one file and < 150 loc
|
64
|
+
|
65
|
+
SAMPLES
|
66
|
+
|
67
|
+
<========< samples/a.rb >========>
|
68
|
+
|
69
|
+
~ > cat samples/a.rb
|
70
|
+
|
71
|
+
#
|
72
|
+
# basic usage is quite, simple, load the config and use it's values. the
|
73
|
+
# config syntax is fairly obvious, i think, but note that it *is* ruby and any
|
74
|
+
# ruby can be included. also note that each config is named, allowing
|
75
|
+
# multiple configs to be places in one file
|
76
|
+
#
|
77
|
+
require 'configuration'
|
78
|
+
|
79
|
+
c = Configuration.load 'a'
|
80
|
+
|
81
|
+
p c.a + c.b - c.c
|
82
|
+
|
83
|
+
~ > ruby samples/a.rb
|
84
|
+
|
85
|
+
42
|
86
|
+
|
87
|
+
|
88
|
+
<========< samples/b.rb >========>
|
89
|
+
|
90
|
+
~ > cat samples/b.rb
|
91
|
+
|
92
|
+
#
|
93
|
+
# configuration.rb supports a very natural nesting syntax. note how values
|
94
|
+
# are scoped in a POLS fashion
|
95
|
+
#
|
96
|
+
require 'configuration'
|
97
|
+
|
98
|
+
c = Configuration.for 'b'
|
99
|
+
|
100
|
+
p c.www.url
|
101
|
+
p c.db.url
|
102
|
+
p c.mail.url
|
103
|
+
|
104
|
+
~ > ruby samples/b.rb
|
105
|
+
|
106
|
+
"http://codeforpeople.com:80"
|
107
|
+
"db://codeforpeople.com:5342"
|
108
|
+
"mail://gmail.com:25"
|
109
|
+
|
110
|
+
|
111
|
+
<========< samples/c.rb >========>
|
112
|
+
|
113
|
+
~ > cat samples/c.rb
|
114
|
+
|
115
|
+
#
|
116
|
+
# configuration.rb let's you keep code very dry.
|
117
|
+
#
|
118
|
+
|
119
|
+
require 'configuration'
|
120
|
+
|
121
|
+
Configuration.load 'c'
|
122
|
+
|
123
|
+
p Configuration.for('development').db
|
124
|
+
p Configuration.for('production').db
|
125
|
+
p Configuration.for('testing').db
|
126
|
+
|
127
|
+
~ > ruby samples/c.rb
|
128
|
+
|
129
|
+
"db/development"
|
130
|
+
"db/production"
|
131
|
+
"db/testing"
|
132
|
+
|
133
|
+
|
134
|
+
<========< samples/d.rb >========>
|
135
|
+
|
136
|
+
~ > cat samples/d.rb
|
137
|
+
|
138
|
+
#
|
139
|
+
# configuration.rb makes use of an external blank slate dsl, this means that
|
140
|
+
# you Configuration objects do, in fact, have all built-in ruby methods such
|
141
|
+
# as #inspect, etc, *unless* you configure over the top of them. the effect
|
142
|
+
# is a configuration object that behaves like a nice ruby object, but which
|
143
|
+
# allows *any* key to be configured
|
144
|
+
#
|
145
|
+
require 'configuration'
|
146
|
+
|
147
|
+
c = Configuration.for 'd'
|
148
|
+
|
149
|
+
p c.object_id
|
150
|
+
p c.inspect
|
151
|
+
p c.p
|
152
|
+
|
153
|
+
~ > ruby samples/d.rb
|
154
|
+
|
155
|
+
42
|
156
|
+
"forty-two"
|
157
|
+
42.0
|
158
|
+
|
159
|
+
|
160
|
+
<========< samples/e.rb >========>
|
161
|
+
|
162
|
+
~ > cat samples/e.rb
|
163
|
+
|
164
|
+
#
|
165
|
+
# configuration.rb uses a totally clean slate dsl for the block. if you need
|
166
|
+
# to access base Object methods you can do this
|
167
|
+
#
|
168
|
+
|
169
|
+
require 'configuration'
|
170
|
+
|
171
|
+
c = Configuration.for 'e'
|
172
|
+
|
173
|
+
p c.foo
|
174
|
+
p c.bar
|
175
|
+
p c.foobar
|
176
|
+
|
177
|
+
~ > ruby samples/e.rb
|
178
|
+
|
179
|
+
42
|
180
|
+
"forty-two"
|
181
|
+
42.0
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
AUTHOR
|
186
|
+
ara.t.howard@gmail.com
|
data/README.erb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
NAME
|
2
|
+
configuration.rb
|
3
|
+
|
4
|
+
SYNOPSIS
|
5
|
+
pure ruby scoped configuration files
|
6
|
+
|
7
|
+
DESCRIPTION
|
8
|
+
configuration.rb provides a mechanism for configuring ruby programs with
|
9
|
+
ruby configuration files. a configuration.rb file, for example
|
10
|
+
'config/app.rb', can be written simply as
|
11
|
+
|
12
|
+
Configuration.for('app'){
|
13
|
+
key 'value'
|
14
|
+
foo 'bar'
|
15
|
+
port 42
|
16
|
+
}
|
17
|
+
|
18
|
+
and loaded via the normal ruby require/load mechanism
|
19
|
+
|
20
|
+
Kernel.load 'config/app.rb'
|
21
|
+
|
22
|
+
or with a slightly augmented loading mechnanism which simply searches an
|
23
|
+
extra set of paths in *addition* to the standard ones
|
24
|
+
|
25
|
+
Configuration.path = %w( config configuration )
|
26
|
+
|
27
|
+
Configuration.load 'app'
|
28
|
+
|
29
|
+
configurations are completely open
|
30
|
+
|
31
|
+
Configuration.for('app'){
|
32
|
+
object_id 'very open'
|
33
|
+
}
|
34
|
+
|
35
|
+
support arbitrarily nested values
|
36
|
+
|
37
|
+
Configuration.for('app'){
|
38
|
+
a { b { c { d 42 } } }
|
39
|
+
}
|
40
|
+
|
41
|
+
c = Configuration.for 'app'
|
42
|
+
|
43
|
+
p c.a.b.c.d #=> 42
|
44
|
+
|
45
|
+
allow POLS scoped lookup of vars
|
46
|
+
|
47
|
+
Configuration.for('config'){
|
48
|
+
outer 'bar'
|
49
|
+
|
50
|
+
inner {
|
51
|
+
value 42
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
c = Configuration.for 'config'
|
56
|
+
|
57
|
+
p c.outer #=> 'bar'
|
58
|
+
p c.inner.value #=> 42
|
59
|
+
p c.inner.outer #=> 'bar'
|
60
|
+
|
61
|
+
|
62
|
+
and not a whole lot else - configuration.rb is s very small library
|
63
|
+
consisting of one file and < 150 loc
|
64
|
+
|
65
|
+
SAMPLES
|
66
|
+
<%= samples %>
|
67
|
+
|
68
|
+
AUTHOR
|
69
|
+
ara.t.howard@gmail.com
|
data/Rakefile
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
This.author = "Ara T. Howard"
|
2
|
+
This.email = "ara.t.howard@gmail.com"
|
3
|
+
This.homepage = "http://github.com/ahoward/#{ This.lib }/tree/master"
|
4
|
+
This.rubyforge_project = 'codeforpeople'
|
5
|
+
|
6
|
+
task :default do
|
7
|
+
puts(Rake::Task.tasks.map{|task| task.name} - ['default'])
|
8
|
+
end
|
9
|
+
|
10
|
+
task :spec do
|
11
|
+
require 'spec/rake/spectask'
|
12
|
+
Spec::Rake::SpecTask.new do |t|
|
13
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
task :gemspec do
|
18
|
+
ignore_extensions = 'git', 'svn', 'tmp', /sw./, 'bak', 'gem'
|
19
|
+
ignore_directories = 'pkg'
|
20
|
+
ignore_files = 'test/log'
|
21
|
+
|
22
|
+
shiteless =
|
23
|
+
lambda do |list|
|
24
|
+
list.delete_if do |entry|
|
25
|
+
next unless test(?e, entry)
|
26
|
+
extension = File.basename(entry).split(%r/[.]/).last
|
27
|
+
ignore_extensions.any?{|ext| ext === extension}
|
28
|
+
end
|
29
|
+
list.delete_if do |entry|
|
30
|
+
next unless test(?d, entry)
|
31
|
+
dirname = File.expand_path(entry)
|
32
|
+
ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
|
33
|
+
end
|
34
|
+
list.delete_if do |entry|
|
35
|
+
next unless test(?f, entry)
|
36
|
+
filename = File.expand_path(entry)
|
37
|
+
ignore_files.any?{|file| File.expand_path(file) == filename}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
lib = This.lib
|
42
|
+
version = This.version
|
43
|
+
files = shiteless[Dir::glob("**/**")]
|
44
|
+
executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
|
45
|
+
has_rdoc = true #File.exist?('doc')
|
46
|
+
test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
|
47
|
+
|
48
|
+
extensions = This.extensions
|
49
|
+
if extensions.nil?
|
50
|
+
%w( Makefile configure extconf.rb ).each do |ext|
|
51
|
+
extensions << ext if File.exists?(ext)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
extensions = [extensions].flatten.compact
|
55
|
+
|
56
|
+
template =
|
57
|
+
if test(?e, 'gemspec.erb')
|
58
|
+
Template{ IO.read('gemspec.erb') }
|
59
|
+
else
|
60
|
+
Template {
|
61
|
+
<<-__
|
62
|
+
## #{ lib }.gemspec
|
63
|
+
#
|
64
|
+
|
65
|
+
Gem::Specification::new do |spec|
|
66
|
+
spec.name = #{ lib.inspect }
|
67
|
+
spec.version = #{ version.inspect }
|
68
|
+
spec.platform = Gem::Platform::RUBY
|
69
|
+
spec.summary = #{ lib.inspect }
|
70
|
+
|
71
|
+
spec.files = #{ files.inspect }
|
72
|
+
spec.executables = #{ executables.inspect }
|
73
|
+
|
74
|
+
<% if test(?d, 'lib') %>
|
75
|
+
spec.require_path = "lib"
|
76
|
+
<% end %>
|
77
|
+
|
78
|
+
spec.has_rdoc = #{ has_rdoc.inspect }
|
79
|
+
spec.test_files = #{ test_files.inspect }
|
80
|
+
#spec.add_dependency 'lib', '>= version'
|
81
|
+
#spec.add_dependency 'fattr'
|
82
|
+
|
83
|
+
spec.extensions.push(*#{ extensions.inspect })
|
84
|
+
|
85
|
+
spec.rubyforge_project = #{ This.rubyforge_project.inspect }
|
86
|
+
spec.author = #{ This.author.inspect }
|
87
|
+
spec.email = #{ This.email.inspect }
|
88
|
+
spec.homepage = #{ This.homepage.inspect }
|
89
|
+
end
|
90
|
+
__
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
open("#{ lib }.gemspec", "w"){|fd| fd.puts template}
|
95
|
+
This.gemspec = "#{ lib }.gemspec"
|
96
|
+
end
|
97
|
+
|
98
|
+
task :gem => [:clean, :gemspec] do
|
99
|
+
Fu.mkdir_p This.pkgdir
|
100
|
+
before = Dir['*.gem']
|
101
|
+
cmd = "gem build #{ This.gemspec }"
|
102
|
+
`#{ cmd }`
|
103
|
+
after = Dir['*.gem']
|
104
|
+
gem = ((after - before).first || after.first) or abort('no gem!')
|
105
|
+
Fu.mv gem, This.pkgdir
|
106
|
+
This.gem = File.basename(gem)
|
107
|
+
end
|
108
|
+
|
109
|
+
task :readme do
|
110
|
+
samples = ''
|
111
|
+
prompt = '~ > '
|
112
|
+
lib = This.lib
|
113
|
+
version = This.version
|
114
|
+
|
115
|
+
Dir['sample*/*'].sort.each do |sample|
|
116
|
+
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
117
|
+
|
118
|
+
cmd = "cat #{ sample }"
|
119
|
+
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
120
|
+
samples << Util.indent(`#{ cmd }`, 4) << "\n"
|
121
|
+
|
122
|
+
cmd = "ruby #{ sample }"
|
123
|
+
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
124
|
+
|
125
|
+
cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -Ilib -Iconfig #{ sample })'"
|
126
|
+
samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
|
127
|
+
end
|
128
|
+
|
129
|
+
template =
|
130
|
+
if test(?e, 'readme.erb')
|
131
|
+
Template{ IO.read('readme.erb') }
|
132
|
+
else
|
133
|
+
Template {
|
134
|
+
<<-__
|
135
|
+
NAME
|
136
|
+
#{ lib }
|
137
|
+
|
138
|
+
DESCRIPTION
|
139
|
+
|
140
|
+
INSTALL
|
141
|
+
gem install #{ lib }
|
142
|
+
|
143
|
+
SAMPLES
|
144
|
+
#{ samples }
|
145
|
+
__
|
146
|
+
}
|
147
|
+
end
|
148
|
+
|
149
|
+
open("README", "w"){|fd| fd.puts template}
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
task :clean do
|
154
|
+
Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
task :release => [:clean, :gemspec, :gem] do
|
159
|
+
gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
|
160
|
+
raise "which one? : #{ gems.inspect }" if gems.size > 1
|
161
|
+
raise "no gems?" if gems.size < 1
|
162
|
+
cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.pkgdir }/#{ This.gem }"
|
163
|
+
puts cmd
|
164
|
+
system cmd
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
BEGIN {
|
172
|
+
$VERBOSE = nil
|
173
|
+
|
174
|
+
require 'ostruct'
|
175
|
+
require 'erb'
|
176
|
+
require 'fileutils'
|
177
|
+
|
178
|
+
Fu = FileUtils
|
179
|
+
|
180
|
+
This = OpenStruct.new
|
181
|
+
|
182
|
+
This.file = File.expand_path(__FILE__)
|
183
|
+
This.dir = File.dirname(This.file)
|
184
|
+
This.pkgdir = File.join(This.dir, 'pkg')
|
185
|
+
|
186
|
+
lib = ENV['LIB']
|
187
|
+
unless lib
|
188
|
+
lib = File.basename(Dir.pwd)
|
189
|
+
end
|
190
|
+
This.lib = lib
|
191
|
+
|
192
|
+
version = ENV['VERSION']
|
193
|
+
unless version
|
194
|
+
name = lib.capitalize
|
195
|
+
library = "./lib/#{ lib }.rb"
|
196
|
+
program = "./bin/#{ lib }"
|
197
|
+
if test(?e, library)
|
198
|
+
require library
|
199
|
+
version = eval(name).send(:version)
|
200
|
+
elsif test(?e, program)
|
201
|
+
version = `#{ program } --version`.strip
|
202
|
+
end
|
203
|
+
abort('no version') if(version.nil? or version.empty?)
|
204
|
+
end
|
205
|
+
This.version = version
|
206
|
+
|
207
|
+
abort('no lib') unless This.lib
|
208
|
+
abort('no version') unless This.version
|
209
|
+
|
210
|
+
module Util
|
211
|
+
def indent(s, n = 2)
|
212
|
+
s = unindent(s)
|
213
|
+
ws = ' ' * n
|
214
|
+
s.gsub(%r/^/, ws)
|
215
|
+
end
|
216
|
+
|
217
|
+
def unindent(s)
|
218
|
+
indent = nil
|
219
|
+
s.each do |line|
|
220
|
+
next if line =~ %r/^\s*$/
|
221
|
+
indent = line[%r/^\s*/] and break
|
222
|
+
end
|
223
|
+
indent ? s.gsub(%r/^#{ indent }/, "") : s
|
224
|
+
end
|
225
|
+
extend self
|
226
|
+
end
|
227
|
+
|
228
|
+
class Template
|
229
|
+
def initialize(&block)
|
230
|
+
@block = block
|
231
|
+
@template = block.call.to_s
|
232
|
+
end
|
233
|
+
def expand(b=nil)
|
234
|
+
ERB.new(Util.unindent(@template)).result(b||@block)
|
235
|
+
end
|
236
|
+
alias_method 'to_s', 'expand'
|
237
|
+
end
|
238
|
+
def Template(*args, &block) Template.new(*args, &block) end
|
239
|
+
|
240
|
+
Dir.chdir(This.dir)
|
241
|
+
}
|
data/config/b.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Configuration.for('b'){
|
2
|
+
host "codeforpeople.com"
|
3
|
+
|
4
|
+
www {
|
5
|
+
port 80
|
6
|
+
url "http://#{ host }:#{ port }"
|
7
|
+
}
|
8
|
+
|
9
|
+
db {
|
10
|
+
port 5342
|
11
|
+
url "db://#{ host }:#{ port }"
|
12
|
+
}
|
13
|
+
|
14
|
+
mail {
|
15
|
+
host "gmail.com"
|
16
|
+
port 25
|
17
|
+
url "mail://#{ host }:#{ port }"
|
18
|
+
}
|
19
|
+
}
|
data/config/c.rb
ADDED
data/config/d.rb
ADDED
data/config/e.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
## configuration.gemspec
|
2
|
+
#
|
3
|
+
|
4
|
+
Gem::Specification::new do |spec|
|
5
|
+
spec.name = "configuration"
|
6
|
+
spec.version = "1.0.0"
|
7
|
+
spec.platform = Gem::Platform::RUBY
|
8
|
+
spec.summary = "configuration"
|
9
|
+
|
10
|
+
spec.files = ["config", "config/a.rb", "config/b.rb", "config/c.rb", "config/d.rb", "config/e.rb", "configuration.gemspec", "lib", "lib/configuration.rb", "Rakefile", "README", "README.erb", "samples", "samples/a.rb", "samples/b.rb", "samples/c.rb", "samples/d.rb", "samples/e.rb"]
|
11
|
+
spec.executables = []
|
12
|
+
|
13
|
+
|
14
|
+
spec.require_path = "lib"
|
15
|
+
|
16
|
+
|
17
|
+
spec.has_rdoc = true
|
18
|
+
spec.test_files = nil
|
19
|
+
#spec.add_dependency 'lib', '>= version'
|
20
|
+
#spec.add_dependency 'fattr'
|
21
|
+
|
22
|
+
spec.extensions.push(*[])
|
23
|
+
|
24
|
+
spec.rubyforge_project = "codeforpeople"
|
25
|
+
spec.author = "Ara T. Howard"
|
26
|
+
spec.email = "ara.t.howard@gmail.com"
|
27
|
+
spec.homepage = "http://github.com/ahoward/configuration/tree/master"
|
28
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
class Configuration
|
2
|
+
Configuration::Version = '1.0.0'
|
3
|
+
def Configuration.version() Configuration::Version end
|
4
|
+
|
5
|
+
Path = [
|
6
|
+
if defined? CONFIGURATION_PATH
|
7
|
+
CONFIGURATION_PATH
|
8
|
+
else
|
9
|
+
ENV['CONFIGURATION_PATH']
|
10
|
+
end
|
11
|
+
].compact.flatten.join(File::PATH_SEPARATOR).split(File::PATH_SEPARATOR)
|
12
|
+
|
13
|
+
Table = Hash.new
|
14
|
+
Error = Class.new StandardError
|
15
|
+
Import = Class.new Error
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def for name, options = nil, &block
|
19
|
+
name = name.to_s
|
20
|
+
if Table.has_key?(name)
|
21
|
+
if options or block
|
22
|
+
configuration = Table[name]
|
23
|
+
Table[name] = DSL.evaluate(configuration, options || {}, &block)
|
24
|
+
else
|
25
|
+
Table[name]
|
26
|
+
end
|
27
|
+
else
|
28
|
+
if options or block
|
29
|
+
Table[name] = new name, options || {}, &block
|
30
|
+
else
|
31
|
+
load name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def path *value
|
37
|
+
return self.path = value.first unless value.empty?
|
38
|
+
Path
|
39
|
+
end
|
40
|
+
|
41
|
+
def path= value
|
42
|
+
Path.clear
|
43
|
+
Path.replace [value].compact.flatten.join(File::PATH_SEPARATOR).split(File::PATH_SEPARATOR)
|
44
|
+
end
|
45
|
+
|
46
|
+
def load name
|
47
|
+
name = name.to_s
|
48
|
+
name = name + '.rb' unless name[%r/\.rb$/]
|
49
|
+
key = name.sub %r/\.rb$/, ''
|
50
|
+
load_path = $LOAD_PATH.dup
|
51
|
+
begin
|
52
|
+
$LOAD_PATH.replace(path + load_path)
|
53
|
+
::Kernel.load name
|
54
|
+
ensure
|
55
|
+
$LOAD_PATH.replace load_path
|
56
|
+
end
|
57
|
+
Table[key]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
send :extend, ClassMethods
|
61
|
+
|
62
|
+
module InstanceMethods
|
63
|
+
attr 'name'
|
64
|
+
|
65
|
+
def initialize *argv, &block
|
66
|
+
options = Hash === argv.last ? argv.pop : Hash.new
|
67
|
+
@name = argv.shift
|
68
|
+
DSL.evaluate(self, options, &block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def method_missing m, *a, &b
|
72
|
+
return(Pure[@__parent].send m, *a, &b) rescue super if @__parent
|
73
|
+
super
|
74
|
+
end
|
75
|
+
end
|
76
|
+
send :include, InstanceMethods
|
77
|
+
|
78
|
+
|
79
|
+
class DSL
|
80
|
+
instance_methods.each do |m|
|
81
|
+
undef_method m unless m[%r/^__/]
|
82
|
+
end
|
83
|
+
|
84
|
+
Kernel.methods.each do |m|
|
85
|
+
next if m[%r/^__/]
|
86
|
+
module_eval <<-code
|
87
|
+
def #{ m }(*a, &b)
|
88
|
+
method_missing '#{ m }', *a, &b
|
89
|
+
end
|
90
|
+
code
|
91
|
+
end
|
92
|
+
|
93
|
+
def Send(m, *a, &b)
|
94
|
+
Method(m).call(*a, &b)
|
95
|
+
end
|
96
|
+
|
97
|
+
def Method m
|
98
|
+
@__configuration.method(m)
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.evaluate configuration, options = {}, &block
|
102
|
+
dsl = new configuration
|
103
|
+
Pure[dsl].instance_eval &block if block
|
104
|
+
options.each{|key, value| Pure[dsl].send key, value}
|
105
|
+
Pure[dsl].instance_eval{ @__configuration }
|
106
|
+
end
|
107
|
+
|
108
|
+
def initialize configuration, &block
|
109
|
+
@__configuration = configuration
|
110
|
+
@__singleton_class =
|
111
|
+
class << @__configuration
|
112
|
+
self
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def __configuration__
|
117
|
+
@__configuration
|
118
|
+
end
|
119
|
+
|
120
|
+
def method_missing m, *a, &b
|
121
|
+
if(a.empty? and b.nil?)
|
122
|
+
return Pure[@__configuration].send(m, *a, &b)
|
123
|
+
end
|
124
|
+
if b
|
125
|
+
raise ArgumentError unless a.empty?
|
126
|
+
parent = @__configuration
|
127
|
+
name = m.to_s
|
128
|
+
configuration =
|
129
|
+
if @__configuration.respond_to?(name) and Configuration === @__configuration.send(name)
|
130
|
+
@__configuration.send name
|
131
|
+
else
|
132
|
+
Configuration.new name
|
133
|
+
end
|
134
|
+
Pure[configuration].instance_eval{ @__parent = parent }
|
135
|
+
DSL.evaluate configuration, &b
|
136
|
+
value = configuration
|
137
|
+
end
|
138
|
+
unless a.empty?
|
139
|
+
value = a.size == 1 ? a.first : a
|
140
|
+
end
|
141
|
+
@__singleton_class.module_eval do
|
142
|
+
define_method(m){ value }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class Pure
|
148
|
+
Instance_Methods = Hash.new
|
149
|
+
|
150
|
+
::Object.instance_methods.each do |m|
|
151
|
+
Instance_Methods[m.to_s] = ::Object.instance_method m
|
152
|
+
undef_method m unless m[%r/^__/]
|
153
|
+
end
|
154
|
+
|
155
|
+
def method_missing m, *a, &b
|
156
|
+
Instance_Methods[m.to_s].bind(@object).call(*a, &b)
|
157
|
+
end
|
158
|
+
|
159
|
+
def initialize object
|
160
|
+
@object = object
|
161
|
+
end
|
162
|
+
|
163
|
+
def Pure.[] object
|
164
|
+
new object
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def Configuration(*a, &b)
|
170
|
+
if a.empty? and b.nil?
|
171
|
+
const_get :Configuration
|
172
|
+
else
|
173
|
+
Configuration.new(*a, &b)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
data/samples/a.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#
|
2
|
+
# basic usage is quite, simple, load the config and use it's values. the
|
3
|
+
# config syntax is fairly obvious, i think, but note that it *is* ruby and any
|
4
|
+
# ruby can be included. also note that each config is named, allowing
|
5
|
+
# multiple configs to be places in one file
|
6
|
+
#
|
7
|
+
require 'configuration'
|
8
|
+
|
9
|
+
c = Configuration.load 'a'
|
10
|
+
|
11
|
+
p c.a + c.b - c.c
|
data/samples/b.rb
ADDED
data/samples/c.rb
ADDED
data/samples/d.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#
|
2
|
+
# configuration.rb makes use of an external blank slate dsl, this means that
|
3
|
+
# you Configuration objects do, in fact, have all built-in ruby methods such
|
4
|
+
# as #inspect, etc, *unless* you configure over the top of them. the effect
|
5
|
+
# is a configuration object that behaves like a nice ruby object, but which
|
6
|
+
# allows *any* key to be configured
|
7
|
+
#
|
8
|
+
require 'configuration'
|
9
|
+
|
10
|
+
c = Configuration.for 'd'
|
11
|
+
|
12
|
+
p c.object_id
|
13
|
+
p c.inspect
|
14
|
+
p c.p
|
data/samples/e.rb
ADDED
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ahoward-configuration
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ara T. Howard
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: ara.t.howard@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- config
|
26
|
+
- config/a.rb
|
27
|
+
- config/b.rb
|
28
|
+
- config/c.rb
|
29
|
+
- config/d.rb
|
30
|
+
- config/e.rb
|
31
|
+
- configuration.gemspec
|
32
|
+
- lib
|
33
|
+
- lib/configuration.rb
|
34
|
+
- Rakefile
|
35
|
+
- README
|
36
|
+
- README.erb
|
37
|
+
- samples
|
38
|
+
- samples/a.rb
|
39
|
+
- samples/b.rb
|
40
|
+
- samples/c.rb
|
41
|
+
- samples/d.rb
|
42
|
+
- samples/e.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/ahoward/configuration/tree/master
|
45
|
+
licenses:
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project: codeforpeople
|
66
|
+
rubygems_version: 1.3.5
|
67
|
+
signing_key:
|
68
|
+
specification_version: 2
|
69
|
+
summary: configuration
|
70
|
+
test_files: []
|
71
|
+
|