arrest 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,13 @@
1
1
  require "arrest/version"
2
2
 
3
+ require "arrest/attributes/has_attributes"
4
+ require "arrest/attributes/converter"
3
5
  require "arrest/source"
4
6
  require "arrest/helper/child_collection"
5
7
  require "arrest/exceptions"
6
8
  require "arrest/http_source"
7
9
  require "arrest/mem_source"
10
+ require "arrest/nested_resource"
8
11
  require "arrest/abstract_resource"
9
12
  require "arrest/root_resource"
10
13
  require "arrest/rest_child"
@@ -4,66 +4,11 @@ require 'time'
4
4
 
5
5
  Scope = Struct.new(:name, :block)
6
6
 
7
- class Boolean
8
- # to have a boolean type for attributes
9
- end
10
-
11
7
  module Arrest
12
-
13
- Attribute = Struct.new(:name, :read_only, :clazz)
14
- CONVERTER = {}
15
-
16
- class Converter
17
- class << self
18
- attr_reader :clazz
19
-
20
- def convert value
21
- if value.is_a?(self.clazz)
22
- value
23
- else
24
- self.parse value
25
- end
26
- end
27
-
28
- def target clazz
29
- @clazz = clazz
30
- CONVERTER[clazz] = self
31
- end
32
- end
33
- end
34
-
35
- class IdentConv < Converter
36
- def self.convert value
37
- value
38
- end
39
- end
40
-
41
- class StringConv < IdentConv
42
- target String
43
- end
44
-
45
- class BooleanConv < IdentConv
46
- target Boolean
47
- end
48
-
49
- class IntegerConv < IdentConv
50
- target Integer
51
- end
52
-
53
- class TimeConv < Converter
54
- target Time
55
-
56
- def self.parse value
57
- Time.parse(value)
58
- end
59
- end
60
-
61
-
62
-
63
8
  class AbstractResource
9
+ include HasAttributes
64
10
  class << self
65
11
 
66
- attr_accessor :fields
67
12
  attr_reader :scopes
68
13
 
69
14
 
@@ -131,12 +76,6 @@ module Arrest
131
76
  class_eval "def #{method_name}; self.parent; end"
132
77
  end
133
78
 
134
- def add_attribute attribute
135
- if @fields == nil
136
- @fields = []
137
- end
138
- @fields << attribute
139
- end
140
79
 
141
80
  def scope name, &block
142
81
  if @scopes == nil
@@ -145,16 +84,6 @@ module Arrest
145
84
  @scopes << Scope.new(name, &block)
146
85
  end
147
86
 
148
- def all_fields
149
- self_fields = self.fields
150
- self_fields ||= []
151
- if self.superclass.respond_to?('fields') && self.superclass.fields != nil
152
- self_fields + self.superclass.fields
153
- else
154
- self_fields
155
- end
156
-
157
- end
158
87
 
159
88
  def read_only_attributes(args)
160
89
  args.each_pair do |name, clazz|
@@ -163,25 +92,6 @@ module Arrest
163
92
  end
164
93
  end
165
94
 
166
- def attribute name, clazz
167
- add_attribute Attribute.new(name, false, clazz)
168
-
169
- send :define_method, "#{name}=" do |v|
170
- self.unstub
171
- self.instance_variable_set("@#{name}", v)
172
- end
173
- send :define_method, "#{name}" do
174
- self.unstub
175
- self.instance_variable_get("@#{name}")
176
- end
177
- end
178
-
179
- def attributes(args)
180
- args.each_pair do |name, clazz|
181
- self.attribute name, clazz
182
- end
183
- end
184
-
185
95
  def belongs_to(*args)
186
96
  arg = args[0]
187
97
  name = arg.to_s.downcase
@@ -193,7 +103,6 @@ module Arrest
193
103
  end
194
104
 
195
105
  end
196
- self.fields = []
197
106
 
198
107
  attr_accessor :id
199
108
  attr_reader :stub
@@ -211,25 +120,7 @@ module Arrest
211
120
 
212
121
  def init_from_hash as_i={}
213
122
  @stub = false
214
- as = {}
215
- as_i.each_pair do |k,v|
216
- as[k.to_sym] = v
217
- end
218
- unless self.class.all_fields == nil
219
- self.class.all_fields.each do |field|
220
- value = as[field.name.to_sym]
221
- if value
222
- converter = CONVERTER[field.clazz]
223
- if converter == nil
224
- puts "No converter for: #{field.clazz.name}"
225
- converter = IdentConv
226
- end
227
- else
228
- converter = IdentConv
229
- end
230
- self.send("#{field.name.to_s}=", converter.convert(value))
231
- end
232
- end
123
+ super
233
124
  end
234
125
 
235
126
 
@@ -238,7 +129,11 @@ module Arrest
238
129
  unless self.class.all_fields == nil
239
130
  self.class.all_fields.find_all{|a| !a.read_only}.each do |field|
240
131
  json_name = StringUtils.classify(field.name.to_s,false)
241
- result[json_name] = self.instance_variable_get("@#{field.name.to_s}")
132
+ val = self.instance_variable_get("@#{field.name.to_s}")
133
+ if val != nil && val.is_a?(NestedResource)
134
+ val = val.to_hash
135
+ end
136
+ result[json_name] = val
242
137
  end
243
138
  end
244
139
  result[:id] = self.id
@@ -0,0 +1,94 @@
1
+ class Boolean
2
+ # to have a boolean type for attributes
3
+ end
4
+
5
+ module Arrest
6
+
7
+ class Attribute
8
+ attr_accessor :name, :read_only, :clazz
9
+ def initialize name, read_only, clazz
10
+ @name = name
11
+ @read_only = read_only
12
+ @clazz = clazz
13
+ end
14
+
15
+ def convert value
16
+ return if value == nil
17
+ converter = CONVERTER[@clazz]
18
+ if converter == nil
19
+ puts "No converter for: #{@clazz.name}"
20
+ converter = IdentConv
21
+ end
22
+ converter.convert value
23
+ end
24
+ end
25
+
26
+ class NestedAttribute < Attribute
27
+ def initialize name, read_only, clazz
28
+ super name, read_only, clazz
29
+ end
30
+
31
+ def convert value
32
+ return unless value
33
+ resolved_class.new value
34
+ end
35
+
36
+ def resolved_class
37
+ if @clazz == nil
38
+ @clazz = Source.mod.const_get(@clazz_name)
39
+ end
40
+ @clazz
41
+ end
42
+ end
43
+
44
+ CONVERTER = {}
45
+
46
+ def add_converter key, converter
47
+ CONVERTER[key] = converter
48
+ end
49
+
50
+ class Converter
51
+ class << self
52
+ attr_reader :clazz
53
+
54
+ def convert value
55
+ if value.is_a?(self.clazz)
56
+ value
57
+ else
58
+ self.parse value
59
+ end
60
+ end
61
+
62
+ def target clazz
63
+ @clazz = clazz
64
+ CONVERTER[clazz] = self
65
+ end
66
+ end
67
+ end
68
+
69
+ class IdentConv < Converter
70
+ def self.convert value
71
+ value
72
+ end
73
+ end
74
+
75
+ class StringConv < IdentConv
76
+ target String
77
+ end
78
+
79
+ class BooleanConv < IdentConv
80
+ target Boolean
81
+ end
82
+
83
+ class IntegerConv < IdentConv
84
+ target Integer
85
+ end
86
+
87
+ class TimeConv < Converter
88
+ target Time
89
+
90
+ def self.parse value
91
+ Time.parse(value)
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,97 @@
1
+ module Arrest
2
+ module HasAttributes
3
+
4
+ def self.included(base) # :nodoc:
5
+ base.extend HasAttributesMethods
6
+ end
7
+
8
+ def unstub
9
+
10
+ end
11
+
12
+ def init_from_hash as_i={}
13
+ as = {}
14
+ as_i.each_pair do |k,v|
15
+ as[k.to_sym] = v
16
+ end
17
+ unless self.class.all_fields == nil
18
+ self.class.all_fields.each do |field|
19
+ value = as[field.name.to_sym]
20
+ converted = field.convert(value)
21
+ self.send("#{field.name.to_s}=", converted)
22
+ end
23
+ end
24
+ end
25
+
26
+ def to_hash
27
+ result = {}
28
+ unless self.class.all_fields == nil
29
+ self.class.all_fields.find_all{|a| !a.read_only}.each do |field|
30
+ json_name = StringUtils.classify(field.name.to_s,false)
31
+ val = self.instance_variable_get("@#{field.name.to_s}")
32
+ if val != nil && val.is_a?(NestedResource)
33
+ val = val.to_hash
34
+ end
35
+ result[json_name] = val
36
+ end
37
+ end
38
+ result
39
+ end
40
+
41
+ module HasAttributesMethods
42
+ attr_accessor :fields
43
+
44
+
45
+ def attribute name, clazz
46
+ add_attribute Attribute.new(name, false, clazz)
47
+
48
+ send :define_method, "#{name}=" do |v|
49
+ self.unstub
50
+ self.instance_variable_set("@#{name}", v)
51
+ end
52
+ send :define_method, "#{name}" do
53
+ self.unstub
54
+ self.instance_variable_get("@#{name}")
55
+ end
56
+ end
57
+
58
+ def attributes(args)
59
+ args.each_pair do |name, clazz|
60
+ self.attribute name, clazz
61
+ end
62
+ end
63
+
64
+ def add_attribute attribute
65
+ if @fields == nil
66
+ @fields = []
67
+ end
68
+ @fields << attribute
69
+ end
70
+
71
+ def all_fields
72
+ self_fields = self.fields
73
+ self_fields ||= []
74
+ if self.superclass.respond_to?('fields') && self.superclass.fields != nil
75
+ self_fields + self.superclass.fields
76
+ else
77
+ self_fields
78
+ end
79
+ end
80
+
81
+ def nested name, clazz
82
+ add_attribute NestedAttribute.new(name, false, clazz)
83
+
84
+ send :define_method, "#{name}=" do |v|
85
+ self.unstub
86
+ self.instance_variable_set("@#{name}", v)
87
+ end
88
+ send :define_method, "#{name}" do
89
+ self.unstub
90
+ self.instance_variable_get("@#{name}")
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,28 @@
1
+ module Arrest
2
+ # A nested resource has no own url
3
+ # It is an embedded entity in an actual RestResource or
4
+ # an other NestedResource
5
+ class NestedResource
6
+ include HasAttributes
7
+
8
+ def initialize h
9
+ init_from_hash h
10
+ end
11
+
12
+ class << self
13
+ def to_hash
14
+ result = {}
15
+ unless self.class.all_fields == nil
16
+ self.class.all_fields.find_all{|a| !a.read_only}.each do |field|
17
+ json_name = StringUtils.classify(field.name.to_s,false)
18
+ result[json_name] = self.instance_variable_get("@#{field.name.to_s}")
19
+ end
20
+ end
21
+ result[:id] = self.id
22
+ result
23
+
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module Arrest
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -30,3 +30,14 @@ class SpecialZoo < Zoo
30
30
 
31
31
  end
32
32
 
33
+ class ANestedClass < Arrest::NestedResource
34
+ attribute :name, String
35
+ attribute :bool, Boolean
36
+ end
37
+
38
+ class WithNested < Arrest::RootResource
39
+ attribute :parent_name, String
40
+ attribute :bool, Boolean
41
+ nested :nested_object, ANestedClass
42
+ end
43
+
@@ -0,0 +1,81 @@
1
+ require 'test/unit'
2
+ load 'test/models.rb'
3
+
4
+ class NestedResourcesTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ Arrest::Source.source = nil
8
+ #Arrest::Source.debug = true
9
+ end
10
+
11
+ def test_instance_test
12
+ n = ANestedClass.new({:name => "foo"})
13
+ assert_equal "foo", n.name
14
+ end
15
+
16
+ def test_from_hash
17
+ input = {
18
+ :parent_name => 'parent',
19
+ :bool => false,
20
+ :nested_object => {
21
+ :name => 'iamnested',
22
+ :bool => true
23
+ }
24
+ }
25
+
26
+ actual = WithNested.new(input)
27
+ assert_equal 'parent', actual.parent_name
28
+ assert_equal false, actual.bool
29
+ puts actual.inspect
30
+ assert actual.respond_to? :nested_object, "The parent object should have an accessor for the nested object"
31
+ assert_equal 'iamnested', actual.nested_object.name
32
+ assert_equal true, actual.nested_object.bool
33
+ end
34
+
35
+ def test_to_hash
36
+ input = {
37
+ :parent_name => 'parent',
38
+ :bool => false,
39
+ :nested_object => {
40
+ :name => 'iamnested',
41
+ :bool => true
42
+ }
43
+ }
44
+
45
+ actual = WithNested.new(input)
46
+
47
+ # we expect camel cased keys
48
+ expected = {
49
+ 'parentName' => 'parent',
50
+ 'bool' => false,
51
+ 'nestedObject' => {
52
+ 'name' => 'iamnested',
53
+ 'bool' => true
54
+ }
55
+ }
56
+
57
+ assert_equal_hashes expected, actual.to_hash
58
+
59
+ end
60
+
61
+ def assert_equal_hashes expected, actual
62
+ assert_equal_hashes_ expected, actual, ''
63
+ end
64
+
65
+ def assert_equal_hashes_ expected, actual, prefix
66
+ more_expected_keys = (expected.keys - actual.keys).map{|k| prefix + k.to_s }
67
+ assert more_expected_keys.empty?, "Actual misses keys: #{more_expected_keys}"
68
+ more_actual_keys = (actual.keys - expected.keys).map{|k| prefix + k.to_s }
69
+ assert more_expected_keys.empty?, "Actual has more keys: #{more_actual_keys}"
70
+
71
+ expected.each_pair do |ek, ev|
72
+ av = actual[ek]
73
+ if ev != nil && ev.is_a?(Hash)
74
+ assert_equal_hashes_ ev, av, "#{prefix}."
75
+ end
76
+ assert_equal ev, av
77
+ end
78
+ end
79
+
80
+
81
+ end
@@ -200,9 +200,9 @@ class FirstTest < Test::Unit::TestCase
200
200
  new_zoo.save
201
201
 
202
202
  assert_not_nil new_zoo.id
203
-
204
203
  # this is where the magic hapens
205
204
  stubbed = Zoo.stub(new_zoo.id)
205
+ return
206
206
 
207
207
  new_animal = Animal.new new_zoo, {:kind => "foo", :age => 42}
208
208
  new_animal.save
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arrest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
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-11-25 00:00:00.000000000Z
12
+ date: 2011-12-02 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
16
- requirement: &10579480 !ruby/object:Gem::Requirement
16
+ requirement: &2162431160 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *10579480
24
+ version_requirements: *2162431160
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: faraday
27
- requirement: &10578980 !ruby/object:Gem::Requirement
27
+ requirement: &2162430460 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - =
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.7.5
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *10578980
35
+ version_requirements: *2162430460
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bundler
38
- requirement: &10578480 !ruby/object:Gem::Requirement
38
+ requirement: &2162429700 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.0.0
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *10578480
46
+ version_requirements: *2162429700
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
- requirement: &10578100 !ruby/object:Gem::Requirement
49
+ requirement: &2162428760 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *10578100
57
+ version_requirements: *2162428760
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rdoc
60
- requirement: &10577640 !ruby/object:Gem::Requirement
60
+ requirement: &2162427040 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *10577640
68
+ version_requirements: *2162427040
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &10577140 !ruby/object:Gem::Requirement
71
+ requirement: &2162426160 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '2'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *10577140
79
+ version_requirements: *2162426160
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rr
82
- requirement: &10576720 !ruby/object:Gem::Requirement
82
+ requirement: &2162425700 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *10576720
90
+ version_requirements: *2162425700
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: simplecov
93
- requirement: &10576260 !ruby/object:Gem::Requirement
93
+ requirement: &2162425100 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *10576260
101
+ version_requirements: *2162425100
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: rack
104
- requirement: &10575840 !ruby/object:Gem::Requirement
104
+ requirement: &2162424460 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,7 +109,7 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *10575840
112
+ version_requirements: *2162424460
113
113
  description: Consume a rest API in a AR like fashion
114
114
  email:
115
115
  - axel.tetzlaff@fortytools.com
@@ -125,10 +125,13 @@ files:
125
125
  - arrest.gemspec
126
126
  - lib/arrest.rb
127
127
  - lib/arrest/abstract_resource.rb
128
+ - lib/arrest/attributes/converter.rb
129
+ - lib/arrest/attributes/has_attributes.rb
128
130
  - lib/arrest/exceptions.rb
129
131
  - lib/arrest/helper/child_collection.rb
130
132
  - lib/arrest/http_source.rb
131
133
  - lib/arrest/mem_source.rb
134
+ - lib/arrest/nested_resource.rb
132
135
  - lib/arrest/rest_child.rb
133
136
  - lib/arrest/root_resource.rb
134
137
  - lib/arrest/source.rb
@@ -138,6 +141,7 @@ files:
138
141
  - spec/spec_helper.rb
139
142
  - spec/support/models/user.rb
140
143
  - test/models.rb
144
+ - test/nested_resource.rb
141
145
  - test/unit.rb
142
146
  homepage: ''
143
147
  licenses: []
@@ -163,4 +167,10 @@ rubygems_version: 1.8.10
163
167
  signing_key:
164
168
  specification_version: 3
165
169
  summary: Another ruby rest client
166
- test_files: []
170
+ test_files:
171
+ - spec/arrest_spec.rb
172
+ - spec/spec_helper.rb
173
+ - spec/support/models/user.rb
174
+ - test/models.rb
175
+ - test/nested_resource.rb
176
+ - test/unit.rb