ahoward-configuration 1.0.0
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/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
|
+
|