ribbon 0.1.0 → 0.2.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/lib/ribbon.rb +54 -34
- data/lib/ribbon/core_ext/hash.rb +1 -1
- data/lib/ribbon/version.rb +1 -1
- data/lib/ribbon/wrapper.rb +122 -0
- metadata +11 -5
- data/lib/ribbon/methods.rb +0 -82
data/lib/ribbon.rb
CHANGED
@@ -1,26 +1,28 @@
|
|
1
|
-
require 'ribbon/methods'
|
2
1
|
require 'ribbon/version'
|
2
|
+
require 'ribbon/wrapper'
|
3
3
|
|
4
|
-
# Ruby Object Notation.
|
4
|
+
# == Ruby Object Notation.
|
5
5
|
#
|
6
|
-
# Inspired by JSON and OpenStruct.
|
6
|
+
# ==== Inspired by JSON and OpenStruct.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
8
|
+
# Ribbons are essentially hashes that use method calls as keys. This is done via
|
9
|
+
# <tt>method_missing</tt>. On top of that, one may still use it as a
|
10
|
+
# general-purpose hash, since the <tt>[key]</tt> and <tt>[key] = value</tt>
|
11
|
+
# methods are defined.
|
10
12
|
#
|
11
13
|
# In order to make room for as many method names as possible, Ribbon inherits
|
12
|
-
# from BasicObject and
|
13
|
-
#
|
14
|
+
# from BasicObject and doesn't implement any methods. Ribbons are designed to be
|
15
|
+
# used together with Ribbon::Wrapper, which provides the methods useful for
|
16
|
+
# computation.
|
14
17
|
class Ribbon < BasicObject
|
15
18
|
|
16
|
-
extend Methods
|
17
|
-
|
18
19
|
# The internal Hash.
|
19
20
|
def __hash__
|
20
21
|
@hash ||= {}
|
21
22
|
end
|
22
23
|
|
23
|
-
#
|
24
|
+
# Initializes the new Ribbon, merging the internal hash with the given one and
|
25
|
+
# converting all internal objects. See Ribbon::convert_all! for details.
|
24
26
|
def initialize(hash = {}, &block)
|
25
27
|
__hash__.merge! hash, &block
|
26
28
|
::Ribbon.convert_all! self
|
@@ -58,31 +60,49 @@ class Ribbon < BasicObject
|
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
61
|
-
#
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
# [:value] Symbol that will be sent to the value in order to obtain its
|
70
|
-
# string representation. Defaults to <tt>:inspect</tt>.
|
71
|
-
#
|
72
|
-
# No matter what is given as the key or value of a
|
73
|
-
def to_s(opts = {})
|
74
|
-
ksym = opts.fetch(:key, :to_s).to_sym
|
75
|
-
vsym = opts.fetch(:value, :inspect).to_sym
|
76
|
-
separator = opts.fetch(:separator, ': ').to_s
|
77
|
-
values = ::Ribbon.map(self) do |k, v|
|
78
|
-
k = if ::Ribbon.instance? k then k.to_s opts else k.send ksym end
|
79
|
-
v = if ::Ribbon.instance? v then v.to_s opts else v.send vsym end
|
80
|
-
"#{k}#{separator}#{v}"
|
81
|
-
end.join ', '
|
82
|
-
"{Ribbon #{values}}"
|
63
|
+
# If <tt>object</tt> is a Hash, converts it to a Ribbon. If it is an Array,
|
64
|
+
# converts any hashes inside.
|
65
|
+
def self.convert(object)
|
66
|
+
case object
|
67
|
+
when ::Hash then self.new object
|
68
|
+
when ::Array then object.map { |element| convert element }
|
69
|
+
else object
|
70
|
+
end
|
83
71
|
end
|
84
72
|
|
85
|
-
#
|
86
|
-
|
73
|
+
# Converts all values in the given Ribbon.
|
74
|
+
def self.convert_all!(ribbon)
|
75
|
+
ribbon.__hash__.each do |key, value|
|
76
|
+
ribbon[key] = case value
|
77
|
+
when self then convert_all! value
|
78
|
+
else convert value
|
79
|
+
end
|
80
|
+
end
|
81
|
+
ribbon
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns +true+ if the given +object+ is a Ribbon.
|
85
|
+
def self.instance?(object)
|
86
|
+
self === object
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns +true+ if the given Ribbon is wrapped.
|
90
|
+
def self.wrapped?(ribbon)
|
91
|
+
Wrapper === ribbon
|
92
|
+
end
|
93
|
+
|
94
|
+
# Wraps a Ribbon instance in a Ribbon::Wrapper.
|
95
|
+
def self.wrap(ribbon)
|
96
|
+
Wrapper.new ribbon
|
97
|
+
end
|
98
|
+
|
99
|
+
class << self
|
100
|
+
|
101
|
+
# Wraps a Ribbon instance in a Ribbon::Wrapper.
|
102
|
+
#
|
103
|
+
# Ribbon[ribbon].keys
|
104
|
+
alias [] wrap
|
105
|
+
|
106
|
+
end
|
87
107
|
|
88
108
|
end
|
data/lib/ribbon/core_ext/hash.rb
CHANGED
data/lib/ribbon/version.rb
CHANGED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'ribbon'
|
2
|
+
|
3
|
+
class Ribbon < BasicObject
|
4
|
+
|
5
|
+
# Wraps around a Ribbon in order to provide general-purpose methods.
|
6
|
+
#
|
7
|
+
# Ribbons are designed to use methods as hash keys. In order to maximize
|
8
|
+
# possibilities, many useful methods were left out of the Ribbon class and
|
9
|
+
# implemented in this wrapper class instead.
|
10
|
+
#
|
11
|
+
# One usually wraps a Ribbon on the fly in order to work with it:
|
12
|
+
#
|
13
|
+
# r = Ribbon.new
|
14
|
+
# Ribbon[r].each { |k, v| p [k,v] }
|
15
|
+
#
|
16
|
+
# If a method the wrapper doesn't respond to is called, it will simply be
|
17
|
+
# forwarded to the wrapped Ribbon:
|
18
|
+
#
|
19
|
+
# w = Ribbon[r]
|
20
|
+
# w.x = 10
|
21
|
+
# w.ribbon.x
|
22
|
+
# => 10
|
23
|
+
class Wrapper
|
24
|
+
|
25
|
+
class << self
|
26
|
+
|
27
|
+
# Wraps a Ribbon instance.
|
28
|
+
#
|
29
|
+
# Ribbon::Wrapper[ribbon]
|
30
|
+
alias [] new
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
# The wrapped Ribbon object.
|
35
|
+
attr_accessor :ribbon
|
36
|
+
|
37
|
+
# Wraps a Ribbon object, providing many general-purpose methods that were
|
38
|
+
# not defined in the Ribbon itself.
|
39
|
+
def initialize(ribbon = Ribbon.new)
|
40
|
+
self.ribbon = ribbon
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the hash of the wrapped Ribbon.
|
44
|
+
def hash
|
45
|
+
ribbon.__hash__
|
46
|
+
end
|
47
|
+
|
48
|
+
# Forwards the method, arguments and block to the wrapped Ribbon's hash, if
|
49
|
+
# it responds to the method, or to the ribbon itself otherwise.
|
50
|
+
def method_missing(method, *args, &block)
|
51
|
+
if hash.respond_to? method then hash
|
52
|
+
else ribbon end.__send__ method, *args, &block
|
53
|
+
end
|
54
|
+
|
55
|
+
# Converts the wrapped Ribbon and all Ribbons inside into hashes.
|
56
|
+
def to_hash
|
57
|
+
to_hash_recursive
|
58
|
+
end
|
59
|
+
|
60
|
+
# Converts the wrapped Ribbon to a hash and serializes it with YAML. To get
|
61
|
+
# a Ribbon back from the serialized hash, you can simply load the hash and
|
62
|
+
# pass it to the Ribbon constructor:
|
63
|
+
#
|
64
|
+
# ribbon = Ribbon.new YAML.load(str)
|
65
|
+
def to_yaml
|
66
|
+
to_hash.to_yaml
|
67
|
+
end
|
68
|
+
|
69
|
+
# Computes a simple key: value string for easy visualization of the wrapped
|
70
|
+
# Ribbon.
|
71
|
+
#
|
72
|
+
# In +opts+ can be specified several options that customize how the string
|
73
|
+
# is generated. Among those options:
|
74
|
+
#
|
75
|
+
# [:separator] Used to separate a key/value pair. Default is <tt>': '</tt>.
|
76
|
+
# [:key] Symbol that will be sent to the key in order to obtain its
|
77
|
+
# string representation. Defaults to <tt>:to_s</tt>.
|
78
|
+
# [:value] Symbol that will be sent to the value in order to obtain its
|
79
|
+
# string representation. Defaults to <tt>:inspect</tt>.
|
80
|
+
def to_s(opts = {})
|
81
|
+
to_s_recursive opts, ribbon
|
82
|
+
end
|
83
|
+
|
84
|
+
# Same as #to_s.
|
85
|
+
alias :inspect :to_s
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# Computes a string value recursively for the given Ribbon and all Ribbons
|
90
|
+
# inside it. This implementation avoids creating additional Ribbon or
|
91
|
+
# Ribbon::Wrapper objects.
|
92
|
+
def to_s_recursive(opts, ribbon)
|
93
|
+
ksym = opts.fetch(:key, :to_s).to_sym
|
94
|
+
vsym = opts.fetch(:value, :inspect).to_sym
|
95
|
+
separator = opts.fetch(:separator, ': ').to_s
|
96
|
+
values = ribbon.__hash__.map do |k, v|
|
97
|
+
k = k.ribbon if Ribbon.wrapped? k
|
98
|
+
v = v.ribbon if Ribbon.wrapped? v
|
99
|
+
k = if Ribbon.instance? k then to_s_recursive opts, k else k.send ksym end
|
100
|
+
v = if Ribbon.instance? v then to_s_recursive opts, v else v.send vsym end
|
101
|
+
"#{k}#{separator}#{v}"
|
102
|
+
end.join ', '
|
103
|
+
"{#{values}}"
|
104
|
+
end
|
105
|
+
|
106
|
+
# Converts the wrapped Ribbon and all Ribbons inside into hashes using
|
107
|
+
# recursion. This implementation avoids the creation of additional Ribbon or
|
108
|
+
# Ribbon::Wrapper objects.
|
109
|
+
def to_hash_recursive(ribbon = self.ribbon)
|
110
|
+
{}.tap do |hash|
|
111
|
+
ribbon.__hash__.each do |key, value|
|
112
|
+
hash[key] = case value
|
113
|
+
when ::Ribbon then to_hash_recursive value
|
114
|
+
when ::Ribbon::Wrapper then to_hash_recursive value.ribbon
|
115
|
+
else value
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
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.2.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-
|
12
|
+
date: 2011-12-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rookie
|
16
|
-
requirement: &
|
16
|
+
requirement: &19808560 !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: *19808560
|
25
25
|
description: Ruby Object Notation. Inspired by JSON and OpenStruct.
|
26
26
|
email: matheus.a.m.moreira@gmail.com
|
27
27
|
executables: []
|
@@ -37,8 +37,8 @@ files:
|
|
37
37
|
- lib/ribbon.rb
|
38
38
|
- lib/ribbon/core_ext.rb
|
39
39
|
- lib/ribbon/core_ext/hash.rb
|
40
|
-
- lib/ribbon/methods.rb
|
41
40
|
- lib/ribbon/version.rb
|
41
|
+
- lib/ribbon/wrapper.rb
|
42
42
|
- ribbon.gemspec
|
43
43
|
homepage: https://github.com/matheusmoreira/ribbon
|
44
44
|
licenses: []
|
@@ -52,12 +52,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
52
|
- - ! '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
hash: 1132984077947899198
|
55
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
59
|
none: false
|
57
60
|
requirements:
|
58
61
|
- - ! '>='
|
59
62
|
- !ruby/object:Gem::Version
|
60
63
|
version: '0'
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
hash: 1132984077947899198
|
61
67
|
requirements: []
|
62
68
|
rubyforge_project:
|
63
69
|
rubygems_version: 1.8.10
|
data/lib/ribbon/methods.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
class Ribbon < BasicObject
|
2
|
-
|
3
|
-
# Methods that operate on Ribbons. These should be included at the class level
|
4
|
-
# in order to keep as many names available for use with ribbons as possible.
|
5
|
-
module Methods
|
6
|
-
|
7
|
-
# Returns the hash keys of the given ribbon.
|
8
|
-
def keys(ribbon)
|
9
|
-
ribbon.__hash__.keys
|
10
|
-
end
|
11
|
-
|
12
|
-
# Yields a key, value pair to the given block.
|
13
|
-
def each(ribbon, &block)
|
14
|
-
ribbon.__hash__.each &block
|
15
|
-
end
|
16
|
-
|
17
|
-
# Yields a key, value pair to the given block and returns an array
|
18
|
-
# containing the values returned by the block on each iteration.
|
19
|
-
def map(ribbon, &block)
|
20
|
-
ribbon.__hash__.map &block
|
21
|
-
end
|
22
|
-
|
23
|
-
# Merges +old+'s hash with +new+'s. This is equivalent to calling
|
24
|
-
# <tt>merge!</tt> on +old+'s hash and passing it +new+'s hash and the given
|
25
|
-
# block.
|
26
|
-
def merge!(old, new, &block)
|
27
|
-
old_hash, new_hash = old.__hash__, new.__hash__
|
28
|
-
old_hash.merge! new_hash, &block
|
29
|
-
end
|
30
|
-
|
31
|
-
# Converts +ribbon+ and all Ribbons inside into hashes.
|
32
|
-
def to_hash(ribbon)
|
33
|
-
{}.tap do |hash|
|
34
|
-
each(ribbon) do |key, value|
|
35
|
-
hash[key] = case value
|
36
|
-
when Ribbon then to_hash value
|
37
|
-
else value
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# If <tt>object</tt> is a Hash, converts it to a Ribbon::Object. If it is
|
44
|
-
# an Array, converts any hashes inside.
|
45
|
-
def convert(object)
|
46
|
-
case object
|
47
|
-
when ::Hash then Ribbon.new object
|
48
|
-
when ::Array then object.map { |element| convert element }
|
49
|
-
else object
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Converts all values in the given ribbon.
|
54
|
-
def convert_all!(ribbon)
|
55
|
-
each(ribbon) do |key, value|
|
56
|
-
ribbon[key] = case value
|
57
|
-
when Ribbon then convert_all! value
|
58
|
-
else convert value
|
59
|
-
end
|
60
|
-
end
|
61
|
-
ribbon
|
62
|
-
end
|
63
|
-
|
64
|
-
# Returns +true+ if the given +object+ is a Ribbon.
|
65
|
-
def instance?(object)
|
66
|
-
Ribbon === object
|
67
|
-
end
|
68
|
-
|
69
|
-
# Converts the ribbon to a hash and serializes it with YAML. To get a ribbon
|
70
|
-
# back from the serialized hash, you can simply load the hash and pass it to
|
71
|
-
# the Ribbon::Object constructor:
|
72
|
-
#
|
73
|
-
# ribbon = Ribbon::Object.new YAML.load(str)
|
74
|
-
def to_yaml(ribbon)
|
75
|
-
to_hash(ribbon).to_yaml
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
require 'ribbon'
|