structure 0.22.0 → 0.22.1

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/structure.rb CHANGED
@@ -7,7 +7,6 @@
7
7
  # end
8
8
  #
9
9
  class Structure
10
- # Summon a Basic Object.
11
10
  unless defined? BasicObject
12
11
  if defined? BlankSlate
13
12
  BasicObject = BlankSlate
@@ -22,12 +21,12 @@ class Structure
22
21
 
23
22
  # A wrapper for lazy-evaluating undeclared classes
24
23
  #
25
- # @note Borrowed from the same-named class in Ohm
24
+ # @note Somewhat borrowed from the same-named class in Ohm
26
25
  class Wrapper < BasicObject
27
26
  # Wraps specified class in a wrapper if it is not already wrapped
28
27
  #
29
- # @param [Class] klass
30
- # @return [Wrapper]
28
+ # @param [Class] klass a class, which may already be wrapped
29
+ # @return [Wrapper] the wrapped class
31
30
  def self.wrap(klass)
32
31
  klass.class == self ? klass : new(klass.to_s)
33
32
  end
@@ -53,8 +52,6 @@ class Structure
53
52
  end
54
53
  end
55
54
 
56
- private
57
-
58
55
  def method_missing(mth, *args, &block)
59
56
  @unwrapped ? super : @unwrapped = true
60
57
  ::Kernel.const_get(@name).send(mth, *args, &block)
@@ -71,7 +68,7 @@ class Structure
71
68
  # @param [Object] default an optional default value
72
69
  def initialize(type, default = nil)
73
70
  @wrapper = Wrapper.wrap(type)
74
- @default = default
71
+ @default = typecast(default)
75
72
  end
76
73
 
77
74
  # @return the default value for the key
@@ -88,7 +85,9 @@ class Structure
88
85
  # @raise [TypeError] value isn't a type
89
86
  # @return [Object] a typecast value
90
87
  def typecast(val)
91
- if val.nil? || val.is_a?(type)
88
+ if val.nil?
89
+ nil
90
+ elsif val.is_a?(type)
92
91
  val.dup rescue val
93
92
  elsif Kernel.respond_to?(type.to_s)
94
93
  Kernel.send(type.to_s, val)
@@ -113,32 +112,17 @@ class Structure
113
112
  # @param [Object] default an optional default value
114
113
  # @raise [NameError] name is already taken
115
114
  def key(name, type = String, default = nil)
116
- name = name.to_sym
117
-
118
- if method_defined?(name)
115
+ if method_defined?(name = name.to_sym)
119
116
  raise NameError, "#{name} is taken"
120
117
  end
121
118
 
122
- if default && !default.is_a?(type)
123
- raise TypeError, "#{default} isn't a #{type}"
124
- end
125
-
126
- # Add key to blueprint.
127
119
  blueprint[name] = Definition.new(type, default)
128
-
129
- # Define getter.
130
- define_method(name) do
131
- @attributes[name]
132
- end
133
-
134
- # Define setter.
120
+ define_method(name) { @attributes[name] }
135
121
  define_method("#{name}=") do |val|
136
- @attributes[name] = self.class.blueprint[name].typecast(val)
122
+ modifiable[name] = blueprint[name].typecast(val)
137
123
  end
138
124
  end
139
125
 
140
- private
141
-
142
126
  def const_missing(name)
143
127
  Wrapper.new(name)
144
128
  end
@@ -158,18 +142,19 @@ class Structure
158
142
 
159
143
  # @return [Hash] a hash representation of the structure
160
144
  def to_hash
161
- @attributes.inject({}) do |a, (k, v)|
162
- a[k] = if v.respond_to?(:to_hash)
163
- v.to_hash
164
- elsif v.is_a?(Array)
165
- v.map { |e| e.respond_to?(:to_hash) ? e.to_hash : e }
166
- else
167
- v
168
- end
145
+ @attributes.inject({}) { |a, (k, v)| a.merge k => hashify(v) }
146
+ end
169
147
 
170
- a
148
+ def hashify(obj)
149
+ if obj.respond_to? :to_hash
150
+ obj.to_hash
151
+ elsif obj.is_a? Array
152
+ obj.map { |e| hashify(e) }
153
+ else
154
+ obj
171
155
  end
172
156
  end
157
+ private :hashify
173
158
 
174
159
  # Compares this object with another object for equality
175
160
  #
@@ -182,9 +167,23 @@ class Structure
182
167
  other.is_a?(self.class) && attributes == other.attributes
183
168
  end
184
169
 
185
- private
186
-
187
170
  def blueprint
188
171
  self.class.blueprint
189
172
  end
173
+ private :blueprint
174
+
175
+ # Used internally to check if the structure is frozen or not before
176
+ # updating a value
177
+ #
178
+ # @note Borrowed from OpenStruct
179
+ def modifiable
180
+ begin
181
+ @modifiable = true
182
+ rescue
183
+ raise TypeError, "can't modify frozen #{self.class}", caller(3)
184
+ end
185
+
186
+ @attributes
187
+ end
188
+ private :modifiable
190
189
  end
@@ -5,6 +5,27 @@ rescue NameError
5
5
  end
6
6
 
7
7
  class Structure
8
+ # JSON methods for a structure
9
+ #
10
+ # Include this in your structure if you need to cast it to JSON and
11
+ # vice versa.
12
+ #
13
+ # @example
14
+ # class Point < Structure
15
+ # include JSON
16
+ #
17
+ # key :x, Integer
18
+ # key :y, Integer
19
+ # end
20
+ #
21
+ # Alternatively, include it in the parent class if you have more than
22
+ # one structure.
23
+ #
24
+ # @example
25
+ # class Structure
26
+ # include JSON
27
+ # end
28
+ #
8
29
  module JSON
9
30
  def self.included(base)
10
31
  base.extend ClassMethods
@@ -46,7 +67,7 @@ class Structure
46
67
  module ClassMethods
47
68
  # Builds a structure out of its JSON representation
48
69
  #
49
- # @param [Hash] hsh a hashified JSON
70
+ # @param [Hash] hsh a hash representation of a JSON
50
71
  # @return [Structure] a structure
51
72
  def json_create(hsh)
52
73
  hsh.delete('json_class')
@@ -1,3 +1,3 @@
1
1
  class Structure
2
- VERSION = '0.22.0'
2
+ VERSION = '0.22.1'
3
3
  end
@@ -70,13 +70,24 @@ class TestStructure < MiniTest::Unit::TestCase
70
70
  assert_equal 'John', other.friends.first.name
71
71
  end
72
72
 
73
+ def test_cant_change_sex_when_frozen
74
+ person = Person.new(:name => 'John')
75
+ person.freeze
76
+ assert_raises(TypeError) { person.name = 'Jane' }
77
+ end
78
+
73
79
  def test_to_hash
74
80
  person = Person.new(:name => 'John')
75
- person.friends << Person.new(:name => 'Jane')
76
- hash = person.to_hash
81
+ friend = Person.new(:name => 'Jane')
82
+ person.friends << friend
83
+ hsh = person.to_hash
84
+
85
+ assert_equal person.name, hsh[:name]
86
+ assert_equal friend.name, hsh[:friends].first[:name]
77
87
 
78
- assert_equal 'John', hash[:name]
79
- assert_equal 'Jane', hash[:friends].first[:name]
88
+ person.friends = [[friend]]
89
+ hsh = person.to_hash
90
+ assert_equal friend.name, hsh[:friends].first.first[:name]
80
91
  end
81
92
 
82
93
  def test_json
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: structure
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.22.0
4
+ version: 0.22.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-26 00:00:00.000000000 Z
12
+ date: 2011-10-27 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Structure is a typed key/value container.
15
15
  email:
@@ -41,18 +41,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
41
41
  - - ! '>='
42
42
  - !ruby/object:Gem::Version
43
43
  version: '0'
44
- segments:
45
- - 0
46
- hash: 2031698207987898845
47
44
  required_rubygems_version: !ruby/object:Gem::Requirement
48
45
  none: false
49
46
  requirements:
50
47
  - - ! '>='
51
48
  - !ruby/object:Gem::Version
52
49
  version: '0'
53
- segments:
54
- - 0
55
- hash: 2031698207987898845
56
50
  requirements: []
57
51
  rubyforge_project: structure
58
52
  rubygems_version: 1.8.10