mod-cons 0.1.1
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/lib/mod_cons.rb +218 -0
- data/lib/tasks/rdoc.rake +32 -0
- metadata +156 -0
data/lib/mod_cons.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
module ModCons
|
2
|
+
|
3
|
+
class Configuration
|
4
|
+
REQUIRED_METHODS = ["[]", "==", "class", "config_changed", "configure", "declare",
|
5
|
+
"initialize", "inspect", "instance_eval", "method_missing",
|
6
|
+
"methods", "to_hash", "to_s"]
|
7
|
+
|
8
|
+
instance_methods.each { |m| undef_method m unless m =~ /^[^a-z]/ or m =~ /\?$/ or REQUIRED_METHODS.include?(m) }
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def declare(namespace = nil, &block)
|
12
|
+
result = self.new(namespace)
|
13
|
+
result.declare(&block)
|
14
|
+
return result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(namespace)
|
19
|
+
@config_changed = []
|
20
|
+
@namespace = namespace
|
21
|
+
@mode = :access
|
22
|
+
@mode_stack = []
|
23
|
+
@table = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def declare(namespace = nil, &block)
|
27
|
+
result = self
|
28
|
+
unless (namespace.nil?)
|
29
|
+
ns = namespace.to_sym
|
30
|
+
if @table[ns]
|
31
|
+
warn "WARNING: Redeclaring configuration namespace #{namespace}"
|
32
|
+
end
|
33
|
+
result = (@table[ns] ||= self.class.new(ns))
|
34
|
+
end
|
35
|
+
if block_given?
|
36
|
+
result._push_mode(:declare, &block)
|
37
|
+
end
|
38
|
+
return(result)
|
39
|
+
end
|
40
|
+
|
41
|
+
def _dispatch_declare(sym, *args, &block)
|
42
|
+
unless sym.to_s =~ /^[A-Za-z][A-Za-z0-9_]+$/
|
43
|
+
raise NameError, "Invalid configuration option name: #{sym}"
|
44
|
+
end
|
45
|
+
if @table[sym]
|
46
|
+
warn "WARNING: Redeclaring configuration option #{sym}"
|
47
|
+
end
|
48
|
+
if block_given?
|
49
|
+
self.declare(sym, &block)
|
50
|
+
else
|
51
|
+
@table[sym] = args.first
|
52
|
+
end
|
53
|
+
return self
|
54
|
+
end
|
55
|
+
|
56
|
+
def _dispatch_config(sym, *args, &block)
|
57
|
+
if @table.has_key?(sym)
|
58
|
+
if @table[sym].is_a?(self.class) and (args.length > 0 or block_given?)
|
59
|
+
@table[sym].configure(*args, &block)
|
60
|
+
elsif args.length == 1
|
61
|
+
@table[sym] = args.first
|
62
|
+
elsif args.length == 0
|
63
|
+
@table[sym]
|
64
|
+
else
|
65
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 1)"
|
66
|
+
end
|
67
|
+
else
|
68
|
+
raise NameError, "Unknown configuration option: #{sym}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def _dispatch_access(sym)
|
73
|
+
if @table.has_key?(sym)
|
74
|
+
@table[sym]
|
75
|
+
else
|
76
|
+
raise NameError, "Unknown configuration option: #{sym}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def method_missing(sym, *args, &block)
|
81
|
+
case @mode
|
82
|
+
when :declare
|
83
|
+
_dispatch_declare(sym, *args, &block)
|
84
|
+
when :config
|
85
|
+
_dispatch_config(sym, *args, &block)
|
86
|
+
else
|
87
|
+
_dispatch_access(sym)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def configure(hash = nil, &block)
|
92
|
+
config_signature = self.to_hash
|
93
|
+
self._push_mode(:config) do
|
94
|
+
if hash
|
95
|
+
hash.each_pair do |k,v|
|
96
|
+
key = k.to_sym
|
97
|
+
unless @table.has_key?(key)
|
98
|
+
raise NameError, "Unknown configuration option: #{key}"
|
99
|
+
end
|
100
|
+
|
101
|
+
if @table[key].is_a?(self.class)
|
102
|
+
@table[key].configure(v)
|
103
|
+
else
|
104
|
+
@table[key] = v
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
self.instance_eval(&block) if block_given?
|
109
|
+
end
|
110
|
+
unless self.to_hash == config_signature
|
111
|
+
@config_changed.each do |listener|
|
112
|
+
listener.call(self)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
return self
|
116
|
+
end
|
117
|
+
|
118
|
+
def config_changed(&block)
|
119
|
+
@config_changed << block
|
120
|
+
return self
|
121
|
+
end
|
122
|
+
|
123
|
+
def template(indent = '')
|
124
|
+
result = "#{indent}#{@namespace.to_s}"
|
125
|
+
if indent.length == 0
|
126
|
+
result << ".configure"
|
127
|
+
end
|
128
|
+
result << " do\n"
|
129
|
+
_keys.sort { |a,b| a.to_s <=> b.to_s }.each do |key|
|
130
|
+
value = @table[key]
|
131
|
+
display_value = nil
|
132
|
+
if value.is_a?(self.class)
|
133
|
+
if value._keys.length == 1 and not value[value._keys.first].is_a?(Hash)
|
134
|
+
child_key = value._keys.first
|
135
|
+
display_value = value[child_key].inspect
|
136
|
+
result << "#{indent} #{key.to_s}.#{child_key}"
|
137
|
+
else
|
138
|
+
result << value.template("#{indent} ")
|
139
|
+
end
|
140
|
+
else
|
141
|
+
result << "#{indent} #{key.to_s}"
|
142
|
+
display_value = value.inspect
|
143
|
+
end
|
144
|
+
|
145
|
+
unless display_value.nil?
|
146
|
+
if display_value[0,1] == '{'
|
147
|
+
display_value = "(#{display_value})"
|
148
|
+
else
|
149
|
+
display_value = " #{display_value}"
|
150
|
+
end
|
151
|
+
result << "#{display_value}\n"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
result << "#{indent}end\n"
|
155
|
+
return(result)
|
156
|
+
end
|
157
|
+
|
158
|
+
def [](key)
|
159
|
+
result = @table[key.to_sym]
|
160
|
+
if result.is_a?(self.class)
|
161
|
+
result.to_hash
|
162
|
+
else
|
163
|
+
result
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def _keys
|
168
|
+
@table.keys
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_hash
|
172
|
+
result = @table.dup
|
173
|
+
result.each_pair do |k,v|
|
174
|
+
if v.is_a?(self.class)
|
175
|
+
result[k] = v.to_hash
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def inspect
|
181
|
+
(initial,rest) = @namespace.to_s.split(//,2)
|
182
|
+
"#<#{initial.to_s.upcase}#{rest}: {#{_keys.join(', ')}}>"
|
183
|
+
end
|
184
|
+
|
185
|
+
def methods
|
186
|
+
super + _keys.collect { |k| k.to_s }
|
187
|
+
end
|
188
|
+
|
189
|
+
protected
|
190
|
+
def _push_mode(new_mode, &block)
|
191
|
+
@mode_stack.push(@mode)
|
192
|
+
@mode = new_mode
|
193
|
+
@table.values.each do |v|
|
194
|
+
if v.is_a?(self.class)
|
195
|
+
v._push_mode(new_mode)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
if block_given?
|
199
|
+
begin
|
200
|
+
self.instance_eval(&block)
|
201
|
+
ensure
|
202
|
+
_pop_mode
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def _pop_mode
|
208
|
+
@table.values.each do |v|
|
209
|
+
if v.is_a?(self.class)
|
210
|
+
v._pop_mode
|
211
|
+
end
|
212
|
+
end
|
213
|
+
@mode = @mode_stack.pop || :access
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
Config = Configuration.new(:"ModCons::Config")
|
218
|
+
end
|
data/lib/tasks/rdoc.rake
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
desc "Generate RDoc"
|
2
|
+
task :doc => ['doc:generate']
|
3
|
+
|
4
|
+
namespace :doc do
|
5
|
+
project_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
6
|
+
doc_destination = File.join(project_root, 'rdoc')
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'yard'
|
10
|
+
require 'yard/rake/yardoc_task'
|
11
|
+
|
12
|
+
YARD::Rake::YardocTask.new(:generate) do |yt|
|
13
|
+
yt.files = Dir.glob(File.join(project_root, 'lib', '*.rb')) +
|
14
|
+
Dir.glob(File.join(project_root, 'lib', '**', '*.rb')) +
|
15
|
+
[ File.join(project_root, 'README.rdoc') ] +
|
16
|
+
[ File.join(project_root, 'LICENSE') ]
|
17
|
+
|
18
|
+
yt.options = ['--output-dir', doc_destination, '--readme', 'README.rdoc']
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
desc "Generate YARD Documentation"
|
22
|
+
task :generate do
|
23
|
+
abort "Please install the YARD gem to generate rdoc."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Remove generated documenation"
|
28
|
+
task :clean do
|
29
|
+
rm_r doc_destination if File.exists?(doc_destination)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mod-cons
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Michael Klein
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-05-11 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: bundler
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rake
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 49
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
- 8
|
47
|
+
- 7
|
48
|
+
version: 0.8.7
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: rcov
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
type: :development
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: rdoc
|
67
|
+
prerelease: false
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
type: :development
|
78
|
+
version_requirements: *id004
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: rspec
|
81
|
+
prerelease: false
|
82
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
hash: 3
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
version: "0"
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id005
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: yard
|
95
|
+
prerelease: false
|
96
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
type: :development
|
106
|
+
version_requirements: *id006
|
107
|
+
description: Self-declaring, self-aware, modular configuration for Ruby apps
|
108
|
+
email:
|
109
|
+
- mbklein@gmail.com
|
110
|
+
executables: []
|
111
|
+
|
112
|
+
extensions: []
|
113
|
+
|
114
|
+
extra_rdoc_files: []
|
115
|
+
|
116
|
+
files:
|
117
|
+
- lib/mod_cons.rb
|
118
|
+
- lib/tasks/rdoc.rake
|
119
|
+
has_rdoc: true
|
120
|
+
homepage: https://github.com/mbklein/mod-cons
|
121
|
+
licenses: []
|
122
|
+
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
hash: 3
|
134
|
+
segments:
|
135
|
+
- 0
|
136
|
+
version: "0"
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
hash: 23
|
143
|
+
segments:
|
144
|
+
- 1
|
145
|
+
- 3
|
146
|
+
- 6
|
147
|
+
version: 1.3.6
|
148
|
+
requirements: []
|
149
|
+
|
150
|
+
rubyforge_project:
|
151
|
+
rubygems_version: 1.6.2
|
152
|
+
signing_key:
|
153
|
+
specification_version: 3
|
154
|
+
summary: Modular Configuration
|
155
|
+
test_files: []
|
156
|
+
|