ribbon 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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'