arrest 0.0.5 → 0.0.6

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,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