ribbon 0.3.1 → 0.4.0

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/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