ribbon 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,9 +1,121 @@
1
1
  # Ribbon
2
2
 
3
- RibBON - RuBy Object Notation
3
+ RuBy Object Notation
4
4
 
5
5
  Inspired by JSON and OpenStruct.
6
6
 
7
+ ## Quick Start
8
+
9
+ A Ribbon is a simple but powerful associative data structure designed to be easy
10
+ and natural to use. It allows the dynamic definition of arbitrary attributes,
11
+ which can easily be nested.
12
+
13
+ > r = Ribbon.new
14
+ > r.a.b.c = :d
15
+ => {}
16
+ > r
17
+ => {a: {b: {c: :d}}}
18
+
19
+ If a property hasn't been set, an empty Ribbon will be used as its value. This
20
+ allows you to easily and seamlessly nest any number of Ribbons. If the property
21
+ _has_ been set, its value will be returned instead.
22
+
23
+ > r.a.b.c
24
+ => :d
25
+
26
+ You can also set the property if you give an argument to the method.
27
+
28
+ > r.a.b.c :e
29
+ => :e
30
+ > r
31
+ => {a: {b: {c: :e}}}
32
+
33
+ If you give it a block, the value of the option will be yielded to it.
34
+
35
+ > Ribbon.new.tap do |config|
36
+ config.music do |music|
37
+ music.file do |file|
38
+ file.extensions %w(flac mp3 ogg wma)
39
+ end
40
+ end
41
+ end
42
+ => {music: {file: {extensions: ["flac", "mp3", "ogg", "wma"]}}}
43
+
44
+ If the block takes no arguments (arity of zero), it will be evaluated in the
45
+ context of the value instance. The above example could be rewritten as:
46
+
47
+ > Ribbon.new.tap do |config|
48
+ config.music do
49
+ music.file do
50
+ file.extensions %w(flac mp3 ogg wma)
51
+ end
52
+ end
53
+ end
54
+ => {music: {file: {extensions: ["flac", "mp3", "ogg", "wma"]}}}
55
+
56
+ If you wish to check if a property has a value, you can simply append a `?` to
57
+ its name. If the property isn't there, `nil` will be returned and no Ribbon will
58
+ be created and stored in its place.
59
+
60
+ > r.z?
61
+ => nil
62
+ > r
63
+ => {}
64
+
65
+ If you append a `!` to the name of the property and give it an argument, the
66
+ value of the property will be set to it and the receiver will be returned,
67
+ allowing you to chain multiple assignments in a single line.
68
+
69
+ > r.a!(:z).s!(:x).d!(:c)
70
+ => {a: :z, s: :x, d: :c}
71
+
72
+ You can also access the properties by key using the `[]` and `[]=` operators.
73
+ They work just like the regular method calls, which means you can chain them.
74
+
75
+ > r[:these_properties][:do_not][:exist]
76
+ > r[:they][:will_be] = :created
77
+
78
+ ### Ribbon Wrappers
79
+
80
+ Since Ribbons inherit from BasicObject, they don't include many general-purpose
81
+ methods. In order to solve that problem, `Ribbon::Wrapper` is provided. With a
82
+ wrapped Ribbon instance, you can treat it as if it were an ordinary hash.
83
+
84
+ > w = Ribbon::Wrapper.new
85
+ > w[:x]
86
+ => nil
87
+ > w.fetch :x, 10
88
+ => 10
89
+
90
+ All undefined methods will be forwarded to the Ribbon's internal hash. However,
91
+ if the hash doesn't respond to the method, it will be forwarded to the Ribbon
92
+ itself. In other words, you can use wrapped ribbons as if they weren't wrapped,
93
+ too.
94
+
95
+ > w.x?
96
+ => nil
97
+ > w.x.y.z = 10
98
+ => 10
99
+
100
+ One big difference to be aware of is that dynamic property creation and access
101
+ via square brackets isn't available with wrapped ribbons, because hashes respond
102
+ to `[]`.
103
+
104
+ > w[:undefined][:property]
105
+ => NoMethodError: undefined method `[]' for nil:NilClass
106
+
107
+ Also noteworthy is the fact that wrapping a ribbon will not modify it; nested
108
+ ribbons will not be wrapped. However, the are the methods `wrap_all!` and
109
+ `unwrap_all!`, which will recursively wrap and unwrap every ribbon,
110
+ respectively, are available.
111
+
112
+ In addition to that, many other useful methods are implemented, such as
113
+ `to_hash`, which recursively converts the ribbon and all nested ribbons to pure
114
+ hashes, and `to_yaml`, which serializes the ribbon in YAML format.
115
+
116
+ Finally, you may access the wrapped ribbon's internal hash using the `hash`
117
+ attribute, and access the wrapped ribbon itself using the `ribbon` attribute.
118
+
7
119
  ---
8
120
 
9
- Extracted from [Acclaim](https://github.com/matheusmoreira/acclaim).
121
+ Originally part of [Acclaim](https://github.com/matheusmoreira/acclaim).
data/lib/ribbon.rb CHANGED
@@ -17,6 +17,19 @@ require 'ribbon/wrapper'
17
17
  # r = Ribbon.new
18
18
  # r.a.b.c = 10
19
19
  #
20
+ # You can also assign properties by passing an argument to the method:
21
+ #
22
+ # r.a.b.c 10
23
+ #
24
+ # If you pass a block, the value will be yielded:
25
+ #
26
+ # r.a { |a| a.b { |b| b.c 10 } }
27
+ #
28
+ # If the block passed takes no arguments, it will be <tt>instance_eval</tt>ed on
29
+ # the value instead:
30
+ #
31
+ # r.a { b { c 10 } }
32
+ #
20
33
  # Appending a <tt>!</tt> to the end of the property sets the value and returns
21
34
  # the receiver:
22
35
  #
@@ -54,12 +67,12 @@ class Ribbon < BasicObject
54
67
  end
55
68
 
56
69
  # Gets a value by key.
57
- def [](key)
58
- __hash__[key] = if __hash__.has_key? key
59
- ::Ribbon.convert __hash__[key]
60
- else
61
- ::Ribbon.new
62
- end
70
+ def [](key, &block)
71
+ value = if __hash__.has_key? key then ::Ribbon.convert __hash__[key]
72
+ else ::Ribbon.new end
73
+ if block.arity.zero? then value.instance_eval &block
74
+ else block.call value end if block
75
+ self[key] = value
63
76
  end
64
77
 
65
78
  # Sets a value by key.
@@ -70,6 +83,8 @@ class Ribbon < BasicObject
70
83
  # Handles the following cases:
71
84
  #
72
85
  # ribbon.method => ribbon[method]
86
+ # ribbon.method value => ribbon[method] = value; ribbon[method]
87
+ # ribbon.method &block => ribbon[method, &block]
73
88
  # ribbon.method = value => ribbon[method] = value
74
89
  # ribbon.method! value => ribbon[method] = value; self
75
90
  # ribbon.method? => ribbon.__hash__[method]
@@ -83,7 +98,8 @@ class Ribbon < BasicObject
83
98
  when '?'
84
99
  self.__hash__[m]
85
100
  else
86
- self[method]
101
+ self[method] = args.first unless args.empty?
102
+ self[method, &block]
87
103
  end
88
104
  end
89
105
 
@@ -148,7 +164,7 @@ class Ribbon < BasicObject
148
164
  end
149
165
 
150
166
  # Wraps a ribbon instance in a Ribbon::Wrapper.
151
- def self.wrap(ribbon)
167
+ def self.wrap(ribbon = Ribbon.new)
152
168
  ::Ribbon::Wrapper.new ribbon
153
169
  end
154
170
 
@@ -11,12 +11,12 @@ class Ribbon < BasicObject
11
11
  # Minor version.
12
12
  #
13
13
  # Increments denote backward-compatible changes and additions.
14
- MINOR = 3
14
+ MINOR = 4
15
15
 
16
16
  # Patch version.
17
17
  #
18
18
  # Increments denote changes in implementation.
19
- PATCH = 1
19
+ PATCH = 0
20
20
 
21
21
  # Build version.
22
22
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ribbon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-30 00:00:00.000000000 Z
12
+ date: 2012-01-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rookie
16
- requirement: &18538300 !ruby/object:Gem::Requirement
16
+ requirement: &18324900 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *18538300
24
+ version_requirements: *18324900
25
25
  description: Ruby Object Notation. Inspired by JSON and OpenStruct.
26
26
  email: matheus.a.m.moreira@gmail.com
27
27
  executables: []
@@ -54,7 +54,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
54
54
  version: '0'
55
55
  segments:
56
56
  - 0
57
- hash: 63380645992066073
57
+ hash: 1159963088107678730
58
58
  required_rubygems_version: !ruby/object:Gem::Requirement
59
59
  none: false
60
60
  requirements:
@@ -63,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
63
  version: '0'
64
64
  segments:
65
65
  - 0
66
- hash: 63380645992066073
66
+ hash: 1159963088107678730
67
67
  requirements: []
68
68
  rubyforge_project:
69
69
  rubygems_version: 1.8.10