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 +114 -2
- data/lib/ribbon.rb +24 -8
- data/lib/ribbon/version.rb +2 -2
- metadata +6 -6
data/README.markdown
CHANGED
@@ -1,9 +1,121 @@
|
|
1
1
|
# Ribbon
|
2
2
|
|
3
|
-
|
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
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
|
data/lib/ribbon/version.rb
CHANGED
@@ -11,12 +11,12 @@ class Ribbon < BasicObject
|
|
11
11
|
# Minor version.
|
12
12
|
#
|
13
13
|
# Increments denote backward-compatible changes and additions.
|
14
|
-
MINOR =
|
14
|
+
MINOR = 4
|
15
15
|
|
16
16
|
# Patch version.
|
17
17
|
#
|
18
18
|
# Increments denote changes in implementation.
|
19
|
-
PATCH =
|
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.
|
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:
|
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: &
|
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: *
|
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:
|
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:
|
66
|
+
hash: 1159963088107678730
|
67
67
|
requirements: []
|
68
68
|
rubyforge_project:
|
69
69
|
rubygems_version: 1.8.10
|