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