structure 0.22.0 → 0.22.1

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