mod-cons 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
+