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.
@@ -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
- # Contains a hash whose keys that are symbols can be accessed via method calls.
9
- # This is done via <tt>method_missing</tt>.
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 implements as many methods as possible at the class
13
- # level.
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
- # Merges the internal hash with the given one.
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
- # Computes a simple key:value string for easy visualization.
62
- #
63
- # In +opts+ can be specified several options that customize how the string
64
- # is generated. Among those options:
65
- #
66
- # [:separator] Used to separate a key/value pair. Default is <tt>': '</tt>.
67
- # [:key] Symbol that will be sent to the key in order to obtain its
68
- # string representation. Defaults to <tt>:to_s</tt>.
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
- # Same as #to_s.
86
- alias :inspect :to_s
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
@@ -6,7 +6,7 @@ class Ribbon < BasicObject
6
6
  # Includes a method to convert hashes to ribbons.
7
7
  module Hash
8
8
 
9
- # Converts this hash to a Ribbon::Object.
9
+ # Converts this hash to a Ribbon.
10
10
  def to_ribbon
11
11
  Ribbon.new self
12
12
  end
@@ -11,7 +11,7 @@ class Ribbon < BasicObject
11
11
  # Minor version.
12
12
  #
13
13
  # Increments denote backward-compatible changes and additions.
14
- MINOR = 1
14
+ MINOR = 2
15
15
 
16
16
  # Patch version.
17
17
  #
@@ -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.1.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-29 00:00:00.000000000 Z
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: &15229760 !ruby/object:Gem::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: *15229760
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
@@ -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'