arrest 0.0.18 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  .bundle
2
2
  .project
3
+ .rvmrc
3
4
  *.gem
4
5
  *.swp
5
6
  coverage
data/lib/arrest.rb CHANGED
@@ -10,6 +10,7 @@ require "arrest/attributes/nested_attribute"
10
10
  require "arrest/attributes/polymorphic_attribute"
11
11
  require "arrest/attributes/belongs_to_attribute"
12
12
  require "arrest/attributes/has_many_attribute"
13
+ require "arrest/attributes/has_many_sub_resource_attribute"
13
14
  require "arrest/attributes/converter"
14
15
  require "arrest/class_utils.rb"
15
16
  require "arrest/string_utils.rb"
@@ -54,21 +54,24 @@ module Arrest
54
54
  method_name = method_name.to_sym
55
55
  clazz_name = StringUtils.singular(method_name.to_s)
56
56
  foreign_key = clazz_name + "_id"
57
+ sub_resource = false
57
58
  if options
58
59
  clazz_name = options[:class_name].to_s unless options[:class_name] == nil
59
60
  foreign_key = "#{StringUtils.underscore(clazz_name)}_id"
60
61
  foreign_key = options[:foreign_key].to_s unless options[:foreign_key] == nil
62
+ sub_resource = !!options[:sub_resource]
61
63
  end
62
64
 
63
65
  url_part = method_name.to_s
64
-
65
- hm_attr = HasManyAttribute.new(ids_field_name,
66
- method_name,
67
- clazz_name,
68
- url_part,
69
- foreign_key)
66
+
67
+ hm_attr = create_has_many_attribute(sub_resource,
68
+ ids_field_name,
69
+ method_name,
70
+ clazz_name,
71
+ url_part,
72
+ foreign_key)
70
73
  add_attribute(hm_attr)
71
-
74
+
72
75
  send :define_method, method_name do
73
76
  if @has_many_collections == nil
74
77
  @has_many_collections = {}
@@ -81,6 +84,23 @@ module Arrest
81
84
  end
82
85
  end
83
86
 
87
+ def create_has_many_attribute(sub_resource, ids_field_name, method_name,
88
+ clazz_name, url_part, foreign_key)
89
+ if sub_resource
90
+ HasManySubResourceAttribute.new(ids_field_name,
91
+ method_name,
92
+ clazz_name,
93
+ url_part,
94
+ foreign_key)
95
+ else
96
+ HasManyAttribute.new(ids_field_name,
97
+ method_name,
98
+ clazz_name,
99
+ url_part,
100
+ foreign_key)
101
+ end
102
+ end
103
+
84
104
  def children(*args)
85
105
  method_name, options = args
86
106
  method_name = method_name.to_sym
@@ -110,7 +130,7 @@ module Arrest
110
130
  end
111
131
 
112
132
 
113
- def scope name, &block
133
+ def scope name, &block
114
134
  if @scopes == nil
115
135
  @scopes = []
116
136
  end
@@ -136,11 +156,21 @@ module Arrest
136
156
 
137
157
  def save
138
158
  if Source.skip_validations || self.valid?
139
- verb = new_record? ? :post : :put
140
- !!AbstractResource::source.send(verb, self)
141
- else
142
- false
159
+ req_type = new_record? ? :post : :put
160
+
161
+ success = !!AbstractResource::source.send(req_type, self)
162
+
163
+ if success # check for special sub resources
164
+ self.class.all_fields.find_all{|f| f.is_a?(HasManySubResourceAttribute)}.each do |attr|
165
+ ids = self.send(attr.name)
166
+ srifn = attr.sub_resource_field_name
167
+ result = !!AbstractResource::source.put_sub_resource(self, srifn, ids)
168
+ return false if !result
169
+ end
170
+ return true
171
+ end
143
172
  end
173
+ false
144
174
  end
145
175
 
146
176
  def new_record?
@@ -155,11 +185,17 @@ module Arrest
155
185
  # convenience method printing curl command
156
186
  def curl
157
187
  hs = ""
158
- Arrest::Source.header_decorator.headers.each_pair do |k,v|
188
+ Arrest::Source.header_decorator.headers.each_pair do |k,v|
159
189
  hs << "-H '#{k}:#{v}'"
160
190
  end
161
191
 
162
192
  "curl #{hs} -v '#{Arrest::Source.source.url}/#{self.resource_location}'"
163
193
  end
194
+
195
+ def == (comparison_object)
196
+ other_class_name = comparison_object.class.name if comparison_object
197
+ other_id = comparison_object.id if comparison_object
198
+ self.class.name == other_class_name && self.id == other_id
199
+ end
164
200
  end
165
201
  end
@@ -79,8 +79,9 @@ module Arrest
79
79
  @fields = []
80
80
  end
81
81
 
82
- def attribute name, clazz
83
- add_attribute Attribute.new(name, false, clazz)
82
+ def attribute name, clazz, attribs = {}
83
+ read_only = !!attribs[:read_only]
84
+ add_attribute Attribute.new(name, read_only, clazz)
84
85
  end
85
86
 
86
87
  def attributes(args)
@@ -1,12 +1,13 @@
1
1
  module Arrest
2
2
  class HasManyAttribute < Attribute
3
3
  attr_reader :method_name, :clazz_name, :url_part, :foreign_key
4
- def initialize(ids_field_name,
4
+ def initialize(ids_field_name,
5
5
  method_name,
6
6
  clazz_name,
7
7
  url_part,
8
- foreign_key)
9
- super(ids_field_name, false, Array)
8
+ foreign_key,
9
+ read_only = false)
10
+ super(ids_field_name, read_only, Array)
10
11
  @method_name = method_name.to_sym
11
12
  @clazz_name = clazz_name.to_sym
12
13
  @url_part = url_part.to_sym
@@ -0,0 +1,17 @@
1
+ module Arrest
2
+ class HasManySubResourceAttribute < HasManyAttribute
3
+ def initialize(ids_field_name,
4
+ method_name,
5
+ clazz_name,
6
+ url_part,
7
+ foreign_key)
8
+ # the read_only is set to sub_resource to avoid sending post request as ids array
9
+ # directly instead of sending the ids to the sub_resource
10
+ super(ids_field_name, method_name, clazz_name, url_part, foreign_key, true)
11
+ end
12
+
13
+ def sub_resource_field_name
14
+ @name
15
+ end
16
+ end
17
+ end
@@ -13,30 +13,30 @@ module Arrest
13
13
  @base
14
14
  end
15
15
 
16
- def add_headers headers
16
+ def add_headers(headers)
17
17
  Arrest::Source.header_decorator.headers.each_pair do |k,v|
18
18
  headers[k.to_s] = v.to_s
19
19
  end
20
20
  end
21
21
 
22
- def get_one sub, filter={}
22
+ def get_one(sub, filter={})
23
23
  response = self.connection().get do |req|
24
- req.url sub, filter
25
- add_headers req.headers
24
+ req.url(sub, filter)
25
+ add_headers(req.headers)
26
26
  end
27
27
  rql = RequestLog.new(:get, "#{sub}#{hash_to_query filter}", nil)
28
28
  rsl = ResponseLog.new(response.env[:status], response.body)
29
29
  Arrest::Source.call_logger.log(rql, rsl)
30
30
  if response.env[:status] != 200
31
- raise Errors::DocumentNotFoundError
31
+ raise Errors::DocumentNotFoundError
32
32
  end
33
33
  response.body
34
34
  end
35
35
 
36
- def get_many sub, filter={}
36
+ def get_many(sub, filter={})
37
37
  response = self.connection().get do |req|
38
- req.url sub, filter
39
- add_headers req.headers
38
+ req.url(sub, filter)
39
+ add_headers(req.headers)
40
40
  end
41
41
  rql = RequestLog.new(:get, "#{sub}#{hash_to_query filter}", nil)
42
42
  rsl = ResponseLog.new(response.env[:status], response.body)
@@ -44,8 +44,8 @@ module Arrest
44
44
  response.body
45
45
  end
46
46
 
47
-
48
- def delete_all resource_path
47
+
48
+ def delete_all(resource_path)
49
49
  response = self.connection().delete do |req|
50
50
  req.url(resource_path)
51
51
  add_headers(req.headers)
@@ -53,15 +53,15 @@ module Arrest
53
53
  rql = RequestLog.new(:delete, "#{resource_path}", nil)
54
54
  rsl = ResponseLog.new(response.env[:status], response.body)
55
55
  Arrest::Source.call_logger.log(rql, rsl)
56
-
56
+
57
57
  response.env[:status] == 200
58
58
  end
59
59
 
60
- def delete rest_resource
60
+ def delete(rest_resource)
61
61
  raise "To delete an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
62
62
  response = self.connection().delete do |req|
63
- req.url rest_resource.resource_location
64
- add_headers req.headers
63
+ req.url(rest_resource.resource_location)
64
+ add_headers(req.headers)
65
65
  end
66
66
  rql = RequestLog.new(:delete, rest_resource.resource_location, nil)
67
67
  rsl = ResponseLog.new(response.env[:status], response.body)
@@ -69,29 +69,40 @@ module Arrest
69
69
  response.env[:status] == 200
70
70
  end
71
71
 
72
- def put rest_resource
72
+ def put_sub_resource(rest_resource, sub_url, ids)
73
+ location = rest_resource.resource_location + "/#{sub_url}"
74
+ #body = {sub_url => ids}.to_json
75
+ body = ids.to_json
76
+
77
+ internal_put(rest_resource, location, body)
78
+ end
79
+
80
+ def put(rest_resource)
73
81
  raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
74
82
  hash = rest_resource.to_jhash
75
83
  hash.delete(:id)
76
84
  hash.delete("id")
77
85
  body = hash.to_json
78
86
 
87
+ internal_put(rest_resource, rest_resource.resource_location, body)
88
+ end
89
+
90
+ def internal_put(rest_resource, location, body)
79
91
  response = self.connection().put do |req|
80
- req.url rest_resource.resource_location
81
- add_headers req.headers
92
+ req.url(location)
93
+ add_headers(req.headers)
82
94
  req.body = body
83
95
  end
84
- rql = RequestLog.new(:put, rest_resource.resource_location, body)
96
+ rql = RequestLog.new(:put, location, body)
85
97
  rsl = ResponseLog.new(response.env[:status], response.body)
86
98
  Arrest::Source.call_logger.log(rql, rsl)
87
99
  if response.env[:status] != 200
88
- err = Arrest::Source.error_handler.convert(response.body, response.env[:status])
89
- rest_resource.errors.add(:base, err)
100
+ handle_errors(rest_resource, response.body, response.env[:status])
90
101
  end
91
102
  response.env[:status] == 200
92
103
  end
93
104
 
94
- def post rest_resource
105
+ def post(rest_resource)
95
106
  raise "new object must have setter for id" unless rest_resource.respond_to?(:id=)
96
107
  raise "new object must not have id" if rest_resource.respond_to?(:id) && rest_resource.id != nil
97
108
  hash = rest_resource.to_jhash
@@ -99,7 +110,7 @@ module Arrest
99
110
  hash.delete('id')
100
111
 
101
112
  hash.delete_if{|k,v| v == nil}
102
-
113
+
103
114
  body = hash.to_json
104
115
  response = self.connection().post do |req|
105
116
  req.url rest_resource.resource_path
@@ -115,11 +126,10 @@ module Arrest
115
126
  rest_resource.id= id
116
127
  true
117
128
  else
118
- err = Arrest::Source.error_handler.convert(response.body, response.env[:status])
119
- rest_resource.errors.add(:base, err)
129
+ handle_errors(rest_resource, response.body, response.env[:status])
120
130
  false
121
131
  end
122
-
132
+
123
133
  end
124
134
 
125
135
  def connection
@@ -145,5 +155,16 @@ module Arrest
145
155
  r
146
156
  end
147
157
 
158
+ private
159
+
160
+ def handle_errors rest_resource, body, status
161
+ err = Arrest::Source.error_handler.convert(body,status)
162
+ if err.is_a?(String)
163
+ rest_resource.errors.add(:base, err)
164
+ else # is_a?(Array)
165
+ err.map{|k,v| rest_resource.errors.add(k,v)}
166
+ end
167
+ end
168
+
148
169
  end
149
170
  end
@@ -33,6 +33,16 @@ module Arrest
33
33
  end
34
34
  end
35
35
 
36
+ def load
37
+ r = source().get_one "#{self.resource_path}"
38
+ body = body_root(r)
39
+ if body == nil || body.empty?
40
+ Arrest::logger.info "DocumentNotFoundError for #{self.resource_path}"
41
+ raise Errors::DocumentNotFoundError.new
42
+ end
43
+ self.build body
44
+ end
45
+
36
46
  def find id
37
47
  if id == nil || "" == id
38
48
  Arrest::logger.info "DocumentNotFoundError: no id given"
@@ -1,3 +1,3 @@
1
1
  module Arrest
2
- VERSION = "0.0.18"
2
+ VERSION = "0.0.19"
3
3
  end
data/test/unit.rb CHANGED
@@ -549,5 +549,47 @@ class FirstTest < Test::Unit::TestCase
549
549
  f1_rel = Foo.find(f1.id)
550
550
  assert f1_rel.other_bars.empty?
551
551
  end
552
+
553
+ def test_equality_non_persistent
554
+ zoo1 = Zoo.new(:name => 'zoo1')
555
+ zoo2 = Zoo.new(:name => 'zoo2')
556
+ zoo1.id = '1'
557
+ zoo2.id = '1'
558
+
559
+ assert zoo1 == zoo2
560
+ assert_equal zoo1, zoo2
561
+ zoo2.id = '2'
562
+ assert zoo1 != zoo2
563
+ assert_not_equal zoo1, zoo2
564
+ end
565
+
566
+ def test_equality
567
+ zoo1 = Zoo.new(:name => 'zoo1')
568
+ zoo2 = Zoo.new(:name => 'zoo2')
569
+
570
+ assert zoo1.save, 'simple zoo should be saveable'
571
+ assert zoo2.save, 'simple zoo should be saveable'
572
+
573
+ assert_not_equal zoo1.id, zoo2.id, 'new zoos should have different ids'
574
+
575
+ assert_not_equal zoo1,zoo2, 'objects with different ids should not be equal'
576
+
577
+ assert_equal zoo1, zoo1, 'An object should be euqual to itself'
578
+
579
+ assert_not_equal zoo1, nil, 'Anactual object should not equal nil'
580
+
581
+ zoo1_reloaded = Zoo.find(zoo1.id)
582
+ assert_not_nil zoo1_reloaded
583
+
584
+ assert zoo1 == zoo1_reloaded, "Objects of the same class with the same id should be equal"
585
+
586
+ foo = Foo.new()
587
+ foo.id = zoo1.id
588
+
589
+ assert_not_equal zoo1, foo, "Objects of different classes should not be euqal, even if they have the same id"
590
+
591
+ zoo1_reloaded.name = 'zoooooo'
592
+ assert_equal zoo1, zoo1_reloaded, "Objects of the same class with the same id should be equal even if they differ in attributes (same as in rails)"
593
+ end
552
594
  end
553
595
 
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.18
4
+ version: 0.0.19
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: 2012-01-25 00:00:00.000000000Z
12
+ date: 2012-01-31 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
16
- requirement: &21375560 !ruby/object:Gem::Requirement
16
+ requirement: &2164553540 !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: *21375560
24
+ version_requirements: *2164553540
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: faraday
27
- requirement: &21374520 !ruby/object:Gem::Requirement
27
+ requirement: &2164549080 !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: *21374520
35
+ version_requirements: *2164549080
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: activemodel
38
- requirement: &21374000 !ruby/object:Gem::Requirement
38
+ requirement: &2164547760 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '3'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *21374000
46
+ version_requirements: *2164547760
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
- requirement: &21363500 !ruby/object:Gem::Requirement
49
+ requirement: &2164546900 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.0.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *21363500
57
+ version_requirements: *2164546900
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rake
60
- requirement: &21363020 !ruby/object:Gem::Requirement
60
+ requirement: &2164545840 !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: *21363020
68
+ version_requirements: *2164545840
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rdoc
71
- requirement: &21362460 !ruby/object:Gem::Requirement
71
+ requirement: &2164544020 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *21362460
79
+ version_requirements: *2164544020
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &21361740 !ruby/object:Gem::Requirement
82
+ requirement: &2164543140 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '2'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *21361740
90
+ version_requirements: *2164543140
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rr
93
- requirement: &21360960 !ruby/object:Gem::Requirement
93
+ requirement: &2164542260 !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: *21360960
101
+ version_requirements: *2164542260
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: simplecov
104
- requirement: &21360500 !ruby/object:Gem::Requirement
104
+ requirement: &2164541340 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *21360500
112
+ version_requirements: *2164541340
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rack
115
- requirement: &21360000 !ruby/object:Gem::Requirement
115
+ requirement: &2164522540 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,7 +120,7 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *21360000
123
+ version_requirements: *2164522540
124
124
  description: Consume a rest API in a AR like fashion
125
125
  email:
126
126
  - axel.tetzlaff@fortytools.com
@@ -142,6 +142,7 @@ files:
142
142
  - lib/arrest/attributes/converter.rb
143
143
  - lib/arrest/attributes/has_attributes.rb
144
144
  - lib/arrest/attributes/has_many_attribute.rb
145
+ - lib/arrest/attributes/has_many_sub_resource_attribute.rb
145
146
  - lib/arrest/attributes/nested_attribute.rb
146
147
  - lib/arrest/attributes/polymorphic_attribute.rb
147
148
  - lib/arrest/class_utils.rb
@@ -191,4 +192,12 @@ rubygems_version: 1.8.10
191
192
  signing_key:
192
193
  specification_version: 3
193
194
  summary: Another ruby rest client
194
- test_files: []
195
+ test_files:
196
+ - spec/arrest_spec.rb
197
+ - spec/spec_helper.rb
198
+ - spec/support/models/user.rb
199
+ - test/has_attributed.rb
200
+ - test/models.rb
201
+ - test/nested_resource.rb
202
+ - test/unit.rb
203
+ - test/validations.rb