o 2.0.2 → 2.0.3

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/.gitignore CHANGED
@@ -1 +1,2 @@
1
1
  *~
2
+ Gemfile.lock
data/Gemfile CHANGED
@@ -1,8 +1,10 @@
1
1
  source :rubygems
2
2
 
3
3
  group :development do
4
+ gem 'rspec'
4
5
  gem 'watchr'
5
6
  gem 'rag'
7
+ gem 'pd'
6
8
  end
7
9
 
8
10
  gemspec
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- O, a configuration libraray for Ruby
1
+ O, a configuration gem for Ruby
2
2
  ====================================
3
3
 
4
4
  **Homepage**: [https://github.com/GutenYe/o](https://github.com/GutenYe/o) <br/>
@@ -7,32 +7,33 @@ O, a configuration libraray for Ruby
7
7
  **Documentation**: [http://rubydoc.info/gems/o/frames](http://rubydoc.info/gems/o/frames) <br/>
8
8
  **Issue Tracker**: [https://github.com/GutenYe/o/issues](https://github.com/GutenYe/o/issues) <br/>
9
9
 
10
- then name `o` comes from option/setting, short and handy, eh-ah~
10
+ The name `o` comes from option/setting, short and handy, eh-ah~
11
11
 
12
12
  Features
13
13
  --------
14
14
 
15
- * support variable, computed attribute
16
- * DSL syntax in pure ruby
17
- * tree way to do configration.
18
- * hash compatibility
15
+ * Variable and computed attribute support
16
+ * Pure Ruby DSL syntax
17
+ * Multiple configuration levels including system, user, and command-line.
18
+ * Hash compatibility
19
19
 
20
20
  Introduction
21
21
  -------------
22
22
 
23
- do configuration at three levels: system, user, cmdline
23
+ The three levels of configuration include system, user, and cmdline:
24
24
 
25
- lib/guten/rc.rb # system level
25
+ APP/lib/guten/rc.rb # system level
26
26
  ~/.gutenrc # user level
27
27
  $ guten --list or ENV[GEMFILE]=x guten # cmdline level
28
-
28
+
29
29
  module Guten
30
- Rc = O.require("guten/rc") + O.require("~/.gutenrc")
30
+ Rc = O.require("guten/rc") + O.require("~/.gutenrc") # require use $:
31
31
  Rc.list = true or Rc.gemfile = ENV[GEMFILE] # from cmdline.
32
32
  end
33
33
 
34
+ a constant works very well in many places, but you are free to use any variable.
34
35
 
35
- ### a completed example ###
36
+ ### An example ###
36
37
 
37
38
  Rc = O do
38
39
  host "localhost"
@@ -48,7 +49,7 @@ do configuration at three levels: system, user, cmdline
48
49
  time proc{|offset| Time.now} # computed attribute
49
50
  end
50
51
 
51
- alternative syntax
52
+ ### An example using alternative syntax ###
52
53
 
53
54
  Rc = O do |c|
54
55
  c.host = "localhost"
@@ -64,7 +65,7 @@ alternative syntax
64
65
  c.time = proc{|offset| Time.now}
65
66
  end
66
67
 
67
- a sugar syntax. _works in a file only_
68
+ ### An example of some sugar syntax. _works in a file only_ ###
68
69
 
69
70
  # file: guten/rc.rb
70
71
  development:
@@ -80,36 +81,50 @@ a sugar syntax. _works in a file only_
80
81
  username "guten"
81
82
  end
82
83
 
83
- this is not pure ruby syntax, but it works.
84
84
 
85
- **WARNNING**: must use \t to indent for this sugar syntax.
86
85
 
87
- ### initialize ###
86
+ **NOTE**: This is not pure ruby syntax, but it works.
87
+ In order for this to work, a tab ("\t") must be used for indention.
88
+
89
+ ### Initialize ###
88
90
 
89
- either way is fine
91
+ In order to initialize the configuration object either of the two ways can be used.
90
92
 
91
93
  Rc = O.new
92
94
  Rc = O.require "guten/rc" # from file
93
95
  Rc = O do
94
96
  a 1
95
97
  end
96
- Rc = O[a:1] # from hash
97
- Rc._merge! O_or_Hash
98
+ Rc = O[a: 1] # from a hash data
99
+ Rc._merge!(a: 1)
98
100
 
99
101
  file: "guten/rc.rb"
100
102
 
101
103
  a 1
102
104
 
105
+ Initalize with a default value
106
+
107
+ Rc = O.new
108
+ p Rc[:hello] #=> nil
109
+ Rc = O.new 1
110
+ p Rc[:hello] #=> 1
111
+ p Rc.hello #=> <#O> be careful here
112
+
113
+ ### Assignment & Access ###
103
114
 
104
- ### assignment & access ###
115
+ Flexibility has been built in to allow for various ways to assign configuration
116
+ data values and access the same values within your application. Here are some
117
+ examples of how this can be done:
105
118
 
106
- either way is fine
119
+ Assignment:
107
120
 
108
121
  Rc.age 1
109
122
  Rc.age = 1
110
123
  Rc[:age] = 1
111
124
  Rc["age"] = 1
112
- ---
125
+
126
+ Access:
127
+
113
128
  Rc.age #=> 1
114
129
  Rc.age? #=> true
115
130
  Rc[:age] #=> 1
@@ -121,15 +136,23 @@ either way is fine
121
136
  c[:age] = 2
122
137
  end
123
138
 
124
- ### node ###
139
+ ### Node ###
125
140
 
126
- Rc.a.b.c 1
141
+ Rc = O.new
142
+ Rc.a.b.c = 1
127
143
  p Rc.a.b.c #=> <#Fixnum 1>
128
144
  p Rc.a.b #=> <#O>
129
145
  p Rc.a #=> <#O>
130
- p Rc.i.dont.exists #=> <#O> #check use #_empty?
146
+ p Rc.i.dont.exists #=> <#O>
131
147
 
132
- ### variable & path ###
148
+ Rc = O.new
149
+ p Rc.a._empty? #=> true # if a node is empty?
150
+ Rc.a.b = 1
151
+ p Rc.a._empty? #=> false
152
+ p O===Rc.a #=> true # if it is a node?
153
+ p O===Rc.a.b #=> false
154
+
155
+ ### Variable & Path ###
133
156
 
134
157
  O do
135
158
  age 1
@@ -146,9 +169,9 @@ either way is fine
146
169
  end
147
170
  end
148
171
 
149
- ### namespace ###
172
+ ### Namespace ###
150
173
 
151
- either way is fine
174
+ Either way is fine:
152
175
 
153
176
  O do
154
177
  mail.stmp.address "stmp.gmail.com"
@@ -157,7 +180,7 @@ either way is fine
157
180
  end
158
181
  end
159
182
 
160
- another example
183
+ Another namespace example:
161
184
 
162
185
  O do
163
186
  age 1
@@ -172,9 +195,9 @@ another example
172
195
  end
173
196
 
174
197
 
175
- ### group ###
198
+ ### Group ###
176
199
 
177
- use namespace or use some seperate files like rails.
200
+ Use namespace or use some separate files like rails.
178
201
 
179
202
  config/
180
203
  applications.rb
@@ -183,7 +206,7 @@ use namespace or use some seperate files like rails.
183
206
  test.rb
184
207
  production.rb
185
208
 
186
- ### computed attribute ###
209
+ ### Computed attribute ###
187
210
 
188
211
  Rc = O do
189
212
  time proc{|n| Time.now}
@@ -193,19 +216,25 @@ use namespace or use some seperate files like rails.
193
216
  Rc.time = 2 # assign new value
194
217
  p Rc[:time] #=> <#Proc>
195
218
 
196
- ### semantic ###
219
+ ### Semantic ###
197
220
 
198
221
  O do
199
222
  is_started no # yes ...
200
223
  end
201
224
 
202
- for a list of semantic methods, see O::Semantics
225
+ Note: for a list of semantic methods, see O::Semantics
226
+
227
+ ### Hash compatibility ###
203
228
 
204
- ### hash compatibility ###
229
+ Internal, datas are stored as a Hash. You can access all hash methods via `_method`
230
+
231
+ Rc = O.new
232
+ Rc.a = 1
233
+ Rc._child #=> {:a=>1}
205
234
 
206
- Rc._keys # access hash method via `_method`
235
+ Rc._keys #=> [:a]
207
236
 
208
- ### temporarily change ###
237
+ ### Temporarily change ###
209
238
 
210
239
  Rc.a = 1
211
240
  Rc._temp do
@@ -214,17 +243,16 @@ for a list of semantic methods, see O::Semantics
214
243
  p Rc.a #=> 1
215
244
 
216
245
 
217
- ### access builtin method inside block ###
246
+ ### Access built-in method inside block ###
218
247
 
219
248
  Rc = O do
220
249
  sleep 10 # is a data. Rc.sleep #=> 10
221
250
  O.sleep 10 # call builtin 'sleep' method
222
251
  end
223
252
 
224
- a list of blocked methods is in O::BUILTIN_METHODS
225
-
253
+ Note: for a list of blocked methods, see O::BUILTIN_METHODS
226
254
 
227
- ### some other examples ###
255
+ ### Additional examples ###
228
256
 
229
257
  O do
230
258
  name do
@@ -243,16 +271,12 @@ a list of blocked methods is in O::BUILTIN_METHODS
243
271
  c.first = "Guten"
244
272
  end
245
273
 
246
-
247
-
248
274
  Contributing
249
275
  -------------
250
276
 
251
- * join the project.
252
- * report bugs/featues to issue tracker.
253
- * fork it and pull a request.
254
- * improve documentation.
255
- * feel free to post any ideas.
277
+ * Feel free to join the project and make contributions (by submitting a pull request)
278
+ * Submit any bugs/features/ideas to github issue tracker
279
+ * Codeing style: https://gist.github.com/1105334
256
280
 
257
281
  Install
258
282
  ----------
data/lib/o.rb CHANGED
@@ -1,277 +1,338 @@
1
1
  libdir = File.dirname(__FILE__)
2
2
  $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
3
 
4
- %w(semantics hash_method_fix parser).each{|n| require "o/#{n}"}
5
-
4
+ %w(
5
+ semantics
6
+ hash_method_fix
7
+ parser
8
+ ).each { |n| require "o/#{n}" }
9
+
10
+ # <#O> is a node, it has _child, _parent and _root attribute.
11
+ #
12
+ # Rc = O do
13
+ # a.b 1
14
+ # a.c do
15
+ # d 2
16
+ # end
17
+ # end
18
+ #
19
+ # p Rc
20
+ # #=> <#O
21
+ # :a => <#O
22
+ # :b => 1
23
+ # :c => <#O
24
+ # :d => 2>>>
25
+ #
26
+ # Rc.a #=> <#O>
27
+ # Rc.a._child #=> {:b => 1, :c => <#O>}
28
+ # Rc.a._parent #=> is Rc
29
+ # Rc.a._root #=> is Rc
30
+ #
31
+ # Rc._parent #=> nil
32
+ # Rc._root #=> is Rc
33
+ #
6
34
  class O
7
- autoload :VERSION, "o/version"
8
-
9
- Error = Class.new Exception
10
- LoadError = Class.new Error
11
-
12
- BUILTIN_METHODS = [ :p, :raise, :sleep, :rand, :srand, :exit, :require, :at_exit, :autoload, :open]
13
-
14
- class << self
15
- public *BUILTIN_METHODS
16
-
17
- # @params [String] content
18
- def eval content=nil, &blk
19
- o = O.new nil
20
- content ? o.instance_eval(Parser.compile(content)) : o.instance_eval(&blk)
21
- o._root
22
- end
23
-
24
- # convert hash, O to O
25
- # @param [O,Hash] data
26
- def [] data
27
- case data
28
- when O
29
- data
30
- when Hash
31
- o = O.new
32
- o._child = data
33
- o
34
- end
35
- end
36
-
37
- # get hash data from obj
38
- #
39
- # @param [O, Hash] obj
40
- #
41
- # @return [Hash]
42
- def get obj
43
- case obj
44
- when Hash
45
- obj
46
- when O
47
- obj._child
48
- end
49
- end
50
-
51
- # load a configuration file,
52
- # use $: and support '~/.gutenrc'
53
- #
54
- # @example
55
- # option = O.load("~/.gutenrc")
56
- #
57
- # option = O.load("/absolute/path/a.rb")
58
- #
59
- # O::Path << "/home"
60
- # option = O.load("guten") #=> try "guten.rb"; then try "guten"
61
- # option = O.load("guten.rb")
62
- #
63
- # @param [String] name
64
- # @return [O]
65
- def require name
66
- path = nil
67
-
68
- # ~/.gutenrc
69
- if name =~ /^~/
70
- file = File.expand_path(name)
71
- path = file if File.exists?(file)
72
-
73
- # /absolute/path/to/rc
74
- elsif File.absolute_path(name) == name
75
- path = name if File.exists?(name)
76
-
77
- # relative/rc
78
- else
79
- catch :break do
80
- $:.each do |p|
81
- ['.rb', ''].each {|ext|
82
- file = File.join(p, name+ext)
83
- if File.exists? file
84
- path = file
85
- throw :break
86
- end
87
- }
88
- end
89
- end
90
- end
91
-
92
- raise LoadError, "can't find file -- #{name}" unless path
93
-
94
- O.eval File.read(path)
95
- end
96
- end
97
-
98
- undef_method *BUILTIN_METHODS
99
- include Semantics
100
- include HashMethodFix
101
-
102
- attr_accessor :_parent, :_child, :_root
103
-
104
- def initialize default=nil, options={}, &blk
105
- @_root = options[:_root]
106
- @_child = Hash.new(default)
107
-
108
- if blk
109
- method = _blk2method(&blk)
110
- if blk.arity == 0
111
- method.call
112
- else
113
- method.call self
114
- end
115
- end
116
- end
117
-
118
- def _temp &blk
119
- data = _child.dup
120
- blk.call
121
- self._child = data
122
- end
123
-
124
- def _parent
125
- @_parent || nil
126
- end
127
-
128
- def _root
129
- @_root || self
130
- end
131
-
132
- def _child= obj
133
- @_child = O.get(obj)
134
- end
135
-
136
- def []= key, value
137
- key = key.respond_to?(:to_sym) ? key.to_sym : key
138
- @_child[key] = value
139
- end
140
-
141
- def [] key
142
- key = key.respond_to?(:to_sym) ? key.to_sym : key
143
- @_child[key]
144
- end
145
-
146
- def == other
147
- _child == other._child
148
- end
149
-
150
- def _dup
151
- o = O.new
152
- o._child = _child.dup
153
- o
154
- end
155
-
156
- def _replace obj
157
- self._child = O.get(obj)
158
- self
159
- end
160
-
161
- def + other
162
- raise Error, "not support type for + -- #{other.inspect}" unless O === other
163
- O.new(_child, other._child)
164
- end
165
-
166
- # convert block to method.
167
- #
168
- # you can call a block with arguments
169
- #
170
- # @example USAGE
171
- # instance_eval(&blk)
172
- # blk2method(&blk).call *args
173
- #
174
- def _blk2method &blk
175
- self.class.class_eval do
176
- define_method(:__blk2method, &blk)
177
- end
178
- method(:__blk2method)
179
- end
180
-
181
-
182
- #
183
- # .name?
184
- # .name= value
185
- # .name value
186
- # ._name
187
- #
188
- # .c
189
- # .a.b.c
190
- #
191
- def method_missing name, *args, &blk
192
- #O.p d 'missing', name, args, blk
193
-
194
- # path: root
195
- if name == :_
196
- return _root
197
-
198
- # relative path.
199
- elsif name =~ /^__+$/
200
- num = name.to_s.count('_') - 1
201
- node = self
202
- num.times {
203
- return unless node
204
- node = node._parent
205
- }
206
- return node
207
-
208
- # .name=
209
- elsif name =~ /(.*)=$/
210
- return @_child[$1.to_sym] = args[0]
211
-
212
- # .name?
213
- elsif name =~ /(.*)\?$/
214
- return !! @_child[$1.to_sym]
215
-
216
- # ._name
217
- elsif name =~ /^_(.*)/
218
- name = $1.to_sym
219
- args.map!{|arg| O===arg ? arg._child : arg}
220
- return @_child.send(name, *args, &blk)
221
-
222
- elsif Proc === @_child[name]
223
- return @_child[name].call *args
224
-
225
- # a.c # return data if has :c
226
- # a.c # create new <#O> if no :c
227
- #
228
- elsif args.empty?
229
-
230
- # a.b.c 1
231
- # a.b do
232
- # c 2
233
- # end
234
- if @_child.has_key?(name)
235
- o = @_child[name]
236
- o.instance_eval(&blk) if blk
237
- return o
238
-
239
- else
240
- next_o = O.new(nil, {_root: _root})
241
- next_o._parent = self
242
- self._child[name] = next_o
243
- next_o.instance_eval(&blk) if blk
244
- return next_o
245
- end
246
-
247
- # .name value
248
- else
249
- @_child[name] = args[0]
250
- return args[0]
251
- end
252
- end
253
-
254
- #
255
- # <#O
256
- # :b => 1
257
- # :c => 2
258
- # :d => <#O
259
- # :c => 2>>
260
- def inspect(indent=" ")
261
- o={rst: ""}
262
- o[:rst] << "<#O\n"
263
- _child.each do |k,v|
264
- o[:rst] << "#{indent}#{k.inspect} => "
265
- o[:rst] << (O === v ? "#{v.inspect(indent+" ")}\n" : "#{v.inspect}\n")
266
- end
267
- o[:rst].rstrip! << ">"
268
- end
269
-
270
- alias to_s inspect
35
+ autoload :VERSION, "o/version"
36
+
37
+ Error = Class.new Exception
38
+ LoadError = Class.new Error
39
+
40
+ BUILTIN_METHODS = [ :p, :raise, :sleep, :rand, :srand, :exit, :require, :at_exit, :autoload, :open]
41
+
42
+ class << self
43
+ public *BUILTIN_METHODS
44
+
45
+ # eval a file/string configuration.
46
+ #
47
+ # @params [String] content
48
+ # @return [O] configuration
49
+ def eval(content=nil, &blk)
50
+ o = O.new nil
51
+ content ? o.instance_eval(Parser.compile(content)) : o.instance_eval(&blk)
52
+
53
+ o._root
54
+ end
55
+
56
+ # convert Hash, O to O
57
+ # @param [O,Hash] data
58
+ # @return [O]
59
+ def [](data)
60
+ case data
61
+ when O
62
+ data
63
+ when Hash
64
+ o = O.new
65
+ o._child = data
66
+ o
67
+ end
68
+ end
69
+
70
+ # get Hash data from any object
71
+ #
72
+ # @param [O, Hash] obj
73
+ # @return [Hash]
74
+ def get(obj)
75
+ case obj
76
+ when Hash
77
+ obj
78
+ when O
79
+ obj._child
80
+ end
81
+ end
82
+
83
+ # load a configuration file,
84
+ # use $: and support '~/.gutenrc'
85
+ #
86
+ # @example
87
+ # Rc = O.require("~/.gutenrc")
88
+ #
89
+ # Rc = O.require("/absolute/path/rc.rb")
90
+ #
91
+ # Rc = O.require("guten/rc") #=> load 'APP/lib/guten/rc.rb'
92
+ # # first try 'guten/rc.rb', then 'guten/rc'
93
+ #
94
+ # @param [String] name
95
+ # @return [O]
96
+ def require(name)
97
+ path = nil
98
+
99
+ # ~/.gutenrc
100
+ if name =~ /^~/
101
+ file = File.expand_path(name)
102
+ path = file if File.exists?(file)
103
+
104
+ # /absolute/path/to/rc
105
+ elsif File.absolute_path(name) == name
106
+ path = name if File.exists?(name)
107
+
108
+ # relative/rc
109
+ else
110
+ catch :break do
111
+ $:.each { |p|
112
+ ['.rb', ''].each { |ext|
113
+ file = File.join(p, name+ext)
114
+ if File.exists? file
115
+ path = file
116
+ throw :break
117
+ end
118
+ }
119
+ }
120
+ end
121
+ end
122
+
123
+ raise LoadError, "can't find file -- #{name}" unless path
124
+
125
+ O.eval File.read(path)
126
+ end
127
+ end
128
+
129
+ undef_method *BUILTIN_METHODS
130
+ include Semantics
131
+ include HashMethodFix
132
+
133
+ # parent node, a <#O>
134
+ attr_accessor :_parent
135
+
136
+ # child node, a hash data
137
+ attr_accessor :_child
138
+
139
+ # root node, a <#O>
140
+ attr_accessor :_root
141
+
142
+ # @param [Object] (nil) default create a new hash with the defalut value
143
+ def initialize(default=nil, options={}, &blk)
144
+ @_root = options[:_root]
145
+ @_child = Hash.new(default)
146
+
147
+ if blk
148
+ method = _blk2method(&blk)
149
+ if blk.arity == 0
150
+ method.call
151
+ else
152
+ method.call self
153
+ end
154
+ end
155
+ end
156
+
157
+ # a temporarily change
158
+ def _temp(&blk)
159
+ data = _child.dup
160
+ blk.call
161
+ self._child = data
162
+
163
+ self
164
+ end
165
+
166
+ def _parent
167
+ @_parent || nil
168
+ end
169
+
170
+ def _root
171
+ @_root || self
172
+ end
173
+
174
+ def _child=(obj)
175
+ @_child = O.get(obj)
176
+ end
177
+
178
+ # set data
179
+ def []=(key, value)
180
+ key = key.respond_to?(:to_sym) ? key.to_sym : key
181
+
182
+ @_child[key] = value
183
+ end
184
+
185
+ # get data
186
+ def [](key)
187
+ key = key.respond_to?(:to_sym) ? key.to_sym : key
188
+
189
+ @_child[key]
190
+ end
191
+
192
+ def ==(other)
193
+ _child == other._child
194
+ end
195
+
196
+ # duplicate
197
+ #
198
+ # @return [O] new <#O>
199
+ def _dup
200
+ o = O.new
201
+ o._child = _child.dup
202
+
203
+ o
204
+ end
205
+
206
+ # replace with a new data
207
+ #
208
+ # @param [Hash,O] obj
209
+ # @return [O] self
210
+ def _replace(obj)
211
+ self._child = O.get(obj)
212
+
213
+ self
214
+ end
215
+
216
+ def +(other)
217
+ raise Error, "not support type for + -- #{other.inspect}" unless O === other
218
+
219
+ O.new _child, other._child
220
+ end
221
+
222
+ # everything goes here.
223
+ #
224
+ # .name?
225
+ # .name= value
226
+ # .name value
227
+ # ._name
228
+ #
229
+ # .c
230
+ # .a.b.c
231
+ #
232
+ def method_missing(name, *args, &blk)
233
+ # path: root
234
+ if name == :_
235
+ return _root
236
+
237
+ # relative path: __
238
+ elsif name =~ /^__+$/
239
+ num = name.to_s.count('_') - 1
240
+ node = self
241
+ num.times {
242
+ return unless node
243
+ node = node._parent
244
+ }
245
+ return node
246
+
247
+ # .name=
248
+ elsif name =~ /(.*)=$/
249
+ return @_child[$1.to_sym] = args[0]
250
+
251
+ # ._name
252
+ elsif name =~ /^_(.*)/
253
+ name = $1.to_sym
254
+ args.map!{|arg| O===arg ? arg._child : arg}
255
+ return @_child.send(name, *args, &blk)
256
+
257
+ # .name?
258
+ elsif name =~ /(.*)\?$/
259
+ return !! @_child[$1.to_sym]
260
+
261
+ elsif Proc === @_child[name]
262
+ return @_child[name].call *args
263
+
264
+ # a.c # return data if has :c
265
+ # a.c # create new <#O> if no :c
266
+ #
267
+ elsif args.empty?
268
+
269
+ # a.b.c 1
270
+ # a.b do
271
+ # c 2
272
+ # end
273
+ if @_child.has_key?(name)
274
+ o = @_child[name]
275
+ o.instance_eval(&blk) if blk
276
+ return o
277
+
278
+ else
279
+ next_o = O.new(nil, {_root: _root})
280
+ next_o._parent = self
281
+ self._child[name] = next_o
282
+ next_o.instance_eval(&blk) if blk
283
+ return next_o
284
+ end
285
+
286
+ # .name value
287
+ else
288
+ @_child[name] = args[0]
289
+ return args[0]
290
+ end
291
+ end
292
+
293
+ # pretty print
294
+ #
295
+ # <#O
296
+ # :b => 1
297
+ # :c => 2
298
+ # :d => <#O
299
+ # :c => 2>>
300
+ def inspect(indent=" ")
301
+ o={rst: ""}
302
+ o[:rst] << "<#O\n"
303
+ _child.each { |k,v|
304
+ o[:rst] << "#{indent}#{k.inspect} => "
305
+ o[:rst] << (O === v ? "#{v.inspect(indent+" ")}\n" : "#{v.inspect}\n")
306
+ }
307
+ o[:rst].rstrip! << ">"
308
+
309
+ o[:rst]
310
+ end
311
+
312
+ alias to_s inspect
313
+
314
+ private
315
+ # convert block to method.
316
+ #
317
+ # you can call a block with arguments
318
+ #
319
+ # @example USAGE
320
+ # instance_eval(&blk)
321
+ # blk2method(&blk).call *args
322
+ #
323
+ def _blk2method(&blk)
324
+ self.class.class_eval {
325
+ define_method(:__blk2method, &blk)
326
+ }
327
+
328
+ method(:__blk2method)
329
+ end
330
+
271
331
  end
272
332
 
273
333
  module Kernel
274
- def O default=nil, &blk
275
- O.new(default, &blk)
276
- end
334
+ # a handy method
335
+ def O(default=nil, &blk)
336
+ O.new default, &blk
337
+ end
277
338
  end
@@ -1,13 +1,26 @@
1
1
  class O
2
- module HashMethodFix
3
- def _merge! obj
4
- _child.merge! O.get(obj)
5
- self
6
- end
2
+ #
3
+ # make some hash methods works for <#O>
4
+ #
5
+ module HashMethodFix
6
+
7
+ # merge new data IN PLACE
8
+ #
9
+ # @params [Hash,O] obj
10
+ # @return [self]
11
+ def _merge! obj
12
+ _child.merge! O.get(obj)
13
+ self
14
+ end
7
15
 
8
- def _merge obj
9
- data = _child.merge(O.get(obj))
10
- O[data]
11
- end
12
- end
16
+ # merge new data
17
+ #
18
+ # @params [Hash,O] obj
19
+ # @return [O] new <#O>
20
+ def _merge obj
21
+ data = _child.merge(O.get(obj))
22
+ O[data]
23
+ end
24
+
25
+ end
13
26
  end
data/lib/o/parser.rb CHANGED
@@ -1,87 +1,99 @@
1
1
  class O
2
- class Parser
3
- attr_reader :content
2
+ # convert sugar syntax
3
+ #
4
+ # develoment:
5
+ # database 'postgresql'
6
+ #
7
+ # to a pure ruby syntax
8
+ #
9
+ # development do
10
+ # database 'postgresql'
11
+ # end
12
+ #
13
+ class Parser
14
+ # the string data.
15
+ attr_reader :content
4
16
 
5
- class << self
6
- def compile content
7
- parser = Parser.new content
8
- parser.compile
9
- end
10
- end
17
+ class << self
18
+ # a handy method for Parser.new(content).compile
19
+ def compile(content)
20
+ parser = Parser.new(content)
11
21
 
12
- def initialize content
13
- @content = content
14
- end
22
+ parser.compile
23
+ end
24
+ end
15
25
 
16
- def compile
17
- script = ""
18
- indent_counts = 0
19
- block_start = false
26
+ def initialize content
27
+ @content = content
28
+ end
20
29
 
21
- scan do |token, statement|
22
- case token
23
- when :block_start
24
- block_start = true
25
- statement = statement.sub(":", " do")
26
- script << statement << "\n"
27
- when :statement
28
- script << statement << "\n"
29
- when :indent
30
- indent_counts += 1
31
- script << "\t"*indent_counts
32
- when :undent
33
- script << "\t"*indent_counts
34
- when :dedent
35
- if block_start
36
- block_start = false
37
- script << "\t"*(indent_counts-1) + "end\n"
38
- else
39
- script << "\t"*(indent_counts-1)
40
- end
41
- indent_counts -= 1
42
- end
43
- end
44
- script
45
- end
46
-
47
- private
48
-
49
- def scan
50
- last_indent = 0
30
+ # compile sugar-syntax into ruby-syntax
31
+ def compile
32
+ script = ""
33
+ indent_counts = 0
34
+ block_start = false
51
35
 
52
- content.scan(/(.*?)(\n+|\Z)/).each do |line, newline|
36
+ scan { |token, statement|
37
+ case token
38
+ when :block_start
39
+ block_start = true
40
+ statement = statement.sub(":", " do")
41
+ script << statement << "\n"
42
+ when :statement
43
+ script << statement << "\n"
44
+ when :indent
45
+ indent_counts += 1
46
+ script << "\t"*indent_counts
47
+ when :undent
48
+ script << "\t"*indent_counts
49
+ when :dedent
50
+ if block_start
51
+ block_start = false
52
+ script << "\t"*(indent_counts-1) + "end\n"
53
+ else
54
+ script << "\t"*(indent_counts-1)
55
+ end
56
+ indent_counts -= 1
57
+ end
58
+ }
53
59
 
54
- _, indents, statement = line.match(/^(\t*)(.*)/).to_a
60
+ script
61
+ end
62
+
63
+ private
64
+ def scan
65
+ last_indent = 0
55
66
 
56
- # indent
57
- # a:
58
- # b 1
59
- # c:
60
- # d 1
61
- # e:
62
- # f 1
63
- # g 1
64
- indent = indents.count("\t")
65
- counts = indent - last_indent
66
- last_indent = indent
67
+ content.scan(/(.*?)(\n+|\Z)/).each { |line, newline|
68
+ _, indents, statement = line.match(/^(\t*)(.*)/).to_a
67
69
 
68
- if counts == 0
69
- yield :undent
70
- else
71
- counts.abs.times {
72
- yield (counts>0 ? :indent : :dedent)
73
- }
74
- end
70
+ # indent
71
+ # a:
72
+ # b 1
73
+ # c:
74
+ # d 1
75
+ # e:
76
+ # f 1
77
+ # g 1
78
+ indent = indents.count("\t")
79
+ counts = indent - last_indent
80
+ last_indent = indent
75
81
 
76
- # statement
77
- if statement =~ /:\s*$/
78
- yield :block_start, statement.gsub(/\s*:\s*$/, ':')
79
- else
80
- yield :statement, statement
81
- end
82
- end
82
+ if counts == 0
83
+ yield :undent
84
+ else
85
+ counts.abs.times {
86
+ yield (counts>0 ? :indent : :dedent)
87
+ }
88
+ end
83
89
 
84
-
85
- end
86
- end
90
+ # statement
91
+ if statement =~ /:\s*$/
92
+ yield :block_start, statement.gsub(/\s*:\s*$/, ':')
93
+ else
94
+ yield :statement, statement
95
+ end
96
+ }
97
+ end
98
+ end
87
99
  end
data/lib/o/semantics.rb CHANGED
@@ -1,12 +1,14 @@
1
1
  class O
2
- module Semantics
3
- # semantic
4
- def no
5
- false
6
- end
2
+ # some semantic names for meaningfull configuration.
3
+ module Semantics
4
+ # @return false
5
+ def no
6
+ false
7
+ end
7
8
 
8
- def yes
9
- true
10
- end
11
- end
9
+ # @return true
10
+ def yes
11
+ true
12
+ end
13
+ end
12
14
  end
data/lib/o/version.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  class O
2
- module VERSION
3
- MAJOR = 2
4
- MINOR = 0
5
- PATCH = 2
6
-
7
- IS = [MAJOR, MINOR, PATCH].join(".")
8
- end
2
+ module VERSION
3
+ MAJOR = 2
4
+ MINOR = 0
5
+ PATCH = 3
6
+ PRE = ''
7
+ IS = [MAJOR, MINOR, PATCH].join(".") + PRE
8
+ end
9
9
  end
data/o.gemspec CHANGED
@@ -4,9 +4,9 @@ require "o/version"
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "o"
6
6
  s.version = O::VERSION::IS
7
- s.summary = "a configuration libraray for Ruby"
7
+ s.summary = "a configuration library for Ruby"
8
8
  s.description = <<-EOF
9
- a coonfiguration libraray for Ruby
9
+ a coonfiguration library for Ruby
10
10
  EOF
11
11
 
12
12
  s.author = "Guten"
@@ -15,7 +15,4 @@ a coonfiguration libraray for Ruby
15
15
  s.rubyforge_project = "xx"
16
16
 
17
17
  s.files = `git ls-files`.split("\n")
18
- #s.executables = ["x"]
19
-
20
- #s.add_dependency "x"
21
18
  end
data/spec/o_spec.rb CHANGED
@@ -82,6 +82,19 @@ describe O do
82
82
  @rc[:a].should == 1
83
83
  end
84
84
  end
85
+
86
+ context "initalize with default value" do
87
+ it "default value is nil" do
88
+ rc = O.new
89
+ rc[:foo].should == nil
90
+ end
91
+
92
+ it "init with default value 1" do
93
+ rc = O.new 1
94
+ rc[:foo].should == 1
95
+ end
96
+ end
97
+
85
98
  it "return <#O> if key doesn't exist" do
86
99
  rc = O.new
87
100
  rc.i.dont.exists.should be_an_instance_of O
@@ -245,6 +258,13 @@ describe O do
245
258
 
246
259
  rc._keys.should == [:a]
247
260
  end
261
+
262
+ it "_method? must comes before method?" do
263
+ rc = O.new
264
+ rc.i._empty?.should be_true
265
+ rc.i.empty?.should be_false
266
+ end
267
+
248
268
  end
249
269
 
250
270
  context "temporarily change" do
data/spec/test_spec.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe O do
4
+ it 'works' do
5
+ o = O.new
6
+ #pd o.i
7
+ end
8
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: o
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 2.0.2
5
+ version: 2.0.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Guten
@@ -10,11 +10,11 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-26 00:00:00 Z
13
+ date: 2011-07-27 00:00:00 Z
14
14
  dependencies: []
15
15
 
16
16
  description: |
17
- a coonfiguration libraray for Ruby
17
+ a coonfiguration library for Ruby
18
18
 
19
19
  email: ywzhaifei@Gmail.com
20
20
  executables: []
@@ -27,7 +27,6 @@ files:
27
27
  - .gitignore
28
28
  - .rspec
29
29
  - Gemfile
30
- - Gemfile.lock
31
30
  - LICENSE
32
31
  - README.md
33
32
  - Ragfile
@@ -46,6 +45,7 @@ files:
46
45
  - spec/o/parser_spec.rb
47
46
  - spec/o_spec.rb
48
47
  - spec/spec_helper.rb
48
+ - spec/test_spec.rb
49
49
  homepage: http://github.com/GutenYe/o
50
50
  licenses: []
51
51
 
@@ -72,6 +72,6 @@ rubyforge_project: xx
72
72
  rubygems_version: 1.8.5
73
73
  signing_key:
74
74
  specification_version: 3
75
- summary: a configuration libraray for Ruby
75
+ summary: a configuration library for Ruby
76
76
  test_files: []
77
77
 
data/Gemfile.lock DELETED
@@ -1,31 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- o (2.0.0)
5
-
6
- GEM
7
- remote: http://rubygems.org/
8
- specs:
9
- activesupport (3.0.9)
10
- pa (1.0.2)
11
- pa (~> 1.0.0)
12
- tagen (~> 1.0.0)
13
- thor (~> 0.14.0)
14
- pd (1.0.2)
15
- rag (1.0.6)
16
- pa (~> 1.0.0)
17
- tagen (~> 1.0.0)
18
- thor (~> 0.14.0)
19
- tagen (1.0.2)
20
- activesupport
21
- pd
22
- thor (0.14.6)
23
- watchr (0.7)
24
-
25
- PLATFORMS
26
- ruby
27
-
28
- DEPENDENCIES
29
- o!
30
- rag
31
- watchr