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.
Files changed (3) hide show
  1. data/lib/mod_cons.rb +218 -0
  2. data/lib/tasks/rdoc.rake +32 -0
  3. 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
@@ -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
+