arrest 0.0.24 → 0.0.25

Sign up to get free protection for your applications and to get access to all the features.
@@ -42,7 +42,7 @@ module Arrest
42
42
  params += args.drop(1)
43
43
  @resource.send(args.first, *params)
44
44
  end
45
-
45
+
46
46
  def load(*args)
47
47
  ext = [@context_provider.get_context] + args
48
48
  @resource.load(*ext)
@@ -55,7 +55,7 @@ module Arrest
55
55
  include ActiveModel::Validations
56
56
  include ActiveModel::Conversion
57
57
  include HasAttributes
58
- attribute :id, String
58
+ attribute :id, String, {:read_only => true}
59
59
 
60
60
  attr_accessor :context
61
61
 
@@ -110,11 +110,13 @@ module Arrest
110
110
  clazz_name = StringUtils.singular(method_name.to_s)
111
111
  foreign_key = clazz_name + "_id"
112
112
  sub_resource = false
113
+ read_only = false
113
114
  if options
114
115
  clazz_name = options[:class_name].to_s unless options[:class_name] == nil
115
116
  foreign_key = "#{StringUtils.underscore(clazz_name)}_id"
116
117
  foreign_key = options[:foreign_key].to_s unless options[:foreign_key] == nil
117
118
  sub_resource = !!options[:sub_resource]
119
+ read_only = options[:read_only]
118
120
  end
119
121
 
120
122
  url_part = method_name.to_s
@@ -124,7 +126,8 @@ module Arrest
124
126
  method_name,
125
127
  clazz_name,
126
128
  url_part,
127
- foreign_key)
129
+ foreign_key,
130
+ read_only)
128
131
  add_attribute(hm_attr)
129
132
 
130
133
  send :define_method, method_name do # e.g. define 'teams' method for notation 'has_many :teams'
@@ -135,7 +138,7 @@ module Arrest
135
138
  end
136
139
 
137
140
  def create_has_many_attribute(sub_resource, ids_field_name, method_name,
138
- clazz_name, url_part, foreign_key)
141
+ clazz_name, url_part, foreign_key, read_only)
139
142
  if sub_resource
140
143
  HasManySubResourceAttribute.new(ids_field_name,
141
144
  method_name,
@@ -147,7 +150,8 @@ module Arrest
147
150
  method_name,
148
151
  clazz_name,
149
152
  url_part,
150
- foreign_key)
153
+ foreign_key,
154
+ read_only)
151
155
  end
152
156
  end
153
157
 
@@ -217,7 +221,7 @@ module Arrest
217
221
  self.class.all_fields.find_all{|f| f.is_a?(HasManySubResourceAttribute)}.each do |attr|
218
222
  ids = self.send(attr.name) # get ids_field e.g. for team has_many :users get 'self.user_ids'
219
223
  srifn = attr.sub_resource_field_name
220
- result = !!AbstractResource::source.put_sub_resource( self, srifn, ids)
224
+ result = !!AbstractResource::source.put_sub_resource(self, srifn, ids)
221
225
  return false if !result
222
226
  end
223
227
  return true
@@ -1,5 +1,19 @@
1
1
  require "arrest/source"
2
2
  module Arrest
3
+
4
+
5
+ class Null
6
+ @@NULL = Null.new()
7
+
8
+ def self.singleton
9
+ @@NULL
10
+ end
11
+
12
+ def to_json(*a)
13
+ 'null'
14
+ end
15
+ end
16
+
3
17
  module HasAttributes
4
18
  attr_accessor :attribute_values
5
19
 
@@ -47,7 +61,7 @@ module Arrest
47
61
  end
48
62
  end
49
63
 
50
- def update_attributes attribute_hash
64
+ def attributes=(attribute_hash = {})
51
65
  fields = self.class.all_fields
52
66
  field_names = fields.map(&:name)
53
67
  attribute_hash.each_pair do |k,v|
@@ -58,9 +72,18 @@ module Arrest
58
72
  self.send("#{k}=", converted)
59
73
  end
60
74
  end
75
+ end
76
+
77
+ def update_attributes(attribute_hash = {})
78
+ self.attributes= attribute_hash
61
79
  self.save
62
80
  end
63
81
 
82
+ def reload
83
+ hash = self.class.find(self.context, self.id).to_hash
84
+ self.attributes= hash
85
+ end
86
+
64
87
  def load_from_stub
65
88
  @load_blk.call
66
89
  @stubbed = false
@@ -140,12 +163,14 @@ module Arrest
140
163
  res
141
164
  end
142
165
 
143
- def nested name, clazz
144
- add_attribute NestedAttribute.new(name, false, clazz)
166
+ def nested name, clazz, options = {}
167
+ read_only = !!options[:read_only]
168
+ add_attribute NestedAttribute.new(name, read_only, clazz)
145
169
  end
146
170
 
147
- def nested_array name, clazz
148
- add_attribute NestedCollection.new(name, false, clazz)
171
+ def nested_array name, clazz, options = {}
172
+ read_only = !!options[:read_only]
173
+ add_attribute NestedCollection.new(name, read_only, clazz)
149
174
  end
150
175
  end
151
176
 
@@ -7,8 +7,8 @@ module Arrest
7
7
  clazz_name,
8
8
  url_part,
9
9
  foreign_key)
10
- # the read_only is set to sub_resource to avoid sending post request as ids array
11
- # directly instead of sending the ids to the sub_resource
10
+ # the read_only is set to true to avoid sending post request as ids array in JSON
11
+ # directly instead of modifying the ids via the sub_resource
12
12
  super(ids_field_name, method_name, clazz_name, url_part, foreign_key, true)
13
13
  end
14
14
 
@@ -2,7 +2,7 @@ require 'arrest/string_utils'
2
2
 
3
3
  module Arrest
4
4
 
5
- RequestLog = Struct.new(:method, :url, :body)
5
+ RequestLog = Struct.new(:method, :url, :body, :headers)
6
6
  ResponseLog = Struct.new(:status, :body)
7
7
  CallLog = Struct.new(:request, :response)
8
8
 
@@ -5,6 +5,8 @@ module Arrest
5
5
 
6
6
  class HttpSource
7
7
 
8
+ attr_reader :base
9
+
8
10
  def initialize base
9
11
  @base = base
10
12
  end
@@ -16,17 +18,20 @@ module Arrest
16
18
  def add_headers(context,headers)
17
19
  decorator = context.header_decorator if context
18
20
  decorator ||= Arrest::Source.header_decorator
19
- decorator.headers.each_pair do |k,v|
21
+ hds = decorator.headers
22
+ hds.each_pair do |k,v|
20
23
  headers[k.to_s] = v.to_s
21
24
  end
25
+ hds
22
26
  end
23
27
 
24
28
  def get_one(context, sub, filter={})
29
+ headers = nil
25
30
  response = self.connection().get do |req|
26
31
  req.url(sub, filter)
27
- add_headers(context, req.headers)
32
+ headers = add_headers(context, req.headers)
28
33
  end
29
- rql = RequestLog.new(:get, "#{sub}#{hash_to_query filter}", nil)
34
+ rql = RequestLog.new(:get, "#{sub}#{hash_to_query filter}", nil, headers)
30
35
  rsl = ResponseLog.new(response.env[:status], response.body)
31
36
  Arrest::Source.call_logger.log(rql, rsl)
32
37
  if response.env[:status] != 200
@@ -40,11 +45,12 @@ module Arrest
40
45
  end
41
46
 
42
47
  def get_many(context, sub, filter={})
48
+ headers = nil
43
49
  response = self.connection().get do |req|
44
50
  req.url(sub, filter)
45
- add_headers(context, req.headers)
51
+ headers = add_headers(context, req.headers)
46
52
  end
47
- rql = RequestLog.new(:get, "#{sub}#{hash_to_query filter}", nil)
53
+ rql = RequestLog.new(:get, "#{sub}#{hash_to_query filter}", nil, headers)
48
54
  rsl = ResponseLog.new(response.env[:status], response.body)
49
55
  Arrest::Source.call_logger.log(rql, rsl)
50
56
  response.body
@@ -52,11 +58,12 @@ module Arrest
52
58
 
53
59
 
54
60
  def delete_all(context, resource_path)
55
- response = self.connection().delete do |req|
61
+ headers = nil
62
+ response = self.connection().delete do |req|
56
63
  req.url(resource_path)
57
- add_headers(context, req.headers)
64
+ headers = add_headers(context, req.headers)
58
65
  end
59
- rql = RequestLog.new(:delete, "#{resource_path}", nil)
66
+ rql = RequestLog.new(:delete, "#{resource_path}", nil, headers)
60
67
  rsl = ResponseLog.new(response.env[:status], response.body)
61
68
  Arrest::Source.call_logger.log(rql, rsl)
62
69
 
@@ -65,11 +72,12 @@ module Arrest
65
72
 
66
73
  def delete(context, rest_resource)
67
74
  raise "To delete an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
75
+ headers = nil
68
76
  response = self.connection().delete do |req|
69
77
  req.url(rest_resource.resource_location)
70
- add_headers(context, req.headers)
78
+ headers = add_headers(context, req.headers)
71
79
  end
72
- rql = RequestLog.new(:delete, rest_resource.resource_location, nil)
80
+ rql = RequestLog.new(:delete, rest_resource.resource_location, nil, headers)
73
81
  rsl = ResponseLog.new(response.env[:status], response.body)
74
82
  Arrest::Source.call_logger.log(rql, rsl)
75
83
  response.env[:status] == 200
@@ -87,7 +95,8 @@ module Arrest
87
95
  hash = rest_resource.to_jhash
88
96
  hash.delete(:id)
89
97
  hash.delete("id")
90
- body = hash.to_json
98
+ insert_nulls!(rest_resource,hash)
99
+ body = JSON.generate(hash)
91
100
 
92
101
  internal_put(rest_resource, rest_resource.resource_location, body)
93
102
  end
@@ -96,12 +105,13 @@ module Arrest
96
105
 
97
106
 
98
107
  def internal_put(rest_resource, location, body)
108
+ headers = nil
99
109
  response = self.connection().put do |req|
100
110
  req.url(location)
101
- add_headers(rest_resource.context, req.headers)
111
+ headers = add_headers(rest_resource.context, req.headers)
102
112
  req.body = body
103
113
  end
104
- rql = RequestLog.new(:put, location, body)
114
+ rql = RequestLog.new(:put, location, body, headers)
105
115
  rsl = ResponseLog.new(response.env[:status], response.body)
106
116
  Arrest::Source.call_logger.log(rql, rsl)
107
117
  if response.env[:status] != 200
@@ -110,6 +120,14 @@ module Arrest
110
120
  response.env[:status] == 200
111
121
  end
112
122
 
123
+ def insert_nulls!(rest_resource, hash)
124
+ rest_resource.class.all_fields.each do |field|
125
+ if !field.read_only && hash[field.json_name] == nil
126
+ hash[field.json_name] = Null.singleton
127
+ end
128
+ end
129
+ end
130
+
113
131
  def post(context, rest_resource)
114
132
  raise "new object must have setter for id" unless rest_resource.respond_to?(:id=)
115
133
  raise "new object must not have id" if rest_resource.respond_to?(:id) && rest_resource.id != nil
@@ -117,15 +135,16 @@ module Arrest
117
135
  hash.delete(:id)
118
136
  hash.delete('id')
119
137
 
120
- hash.delete_if{|k,v| v == nil}
138
+ insert_nulls!(rest_resource,hash)
121
139
 
122
- body = hash.to_json
140
+ body = JSON.generate(hash)
141
+ headers = nil
123
142
  response = self.connection().post do |req|
124
143
  req.url rest_resource.resource_path
125
- add_headers(context, req.headers)
144
+ headers = add_headers(context, req.headers)
126
145
  req.body = body
127
146
  end
128
- rql = RequestLog.new(:post, rest_resource.resource_path, body)
147
+ rql = RequestLog.new(:post, rest_resource.resource_path, body, headers)
129
148
  rsl = ResponseLog.new(response.env[:status], response.body)
130
149
  Arrest::Source.call_logger.log(rql, rsl)
131
150
  if (response.env[:status] == 201)
@@ -169,8 +188,16 @@ module Arrest
169
188
  err = Arrest::Source.error_handler.convert(body,status)
170
189
  if err.is_a?(String)
171
190
  rest_resource.errors.add(:base, err)
172
- else # is_a?(Array)
173
- err.map{|k,v| rest_resource.errors.add(k,v)}
191
+ else
192
+ err.map do |k,v|
193
+ if v.is_a?(String)
194
+ rest_resource.errors.add(k,v)
195
+ else
196
+ v.map do |msg|
197
+ rest_resource.errors.add(k,msg)
198
+ end
199
+ end
200
+ end
174
201
  end
175
202
  end
176
203
 
@@ -29,7 +29,9 @@ module Arrest
29
29
  end
30
30
  body ||= []
31
31
  body.map do |h|
32
- self.build h
32
+ obj = self.build h
33
+ obj.context = context
34
+ obj
33
35
  end
34
36
  end
35
37
 
@@ -40,7 +42,9 @@ module Arrest
40
42
  Arrest::logger.info "DocumentNotFoundError for #{self.resource_path}"
41
43
  raise Errors::DocumentNotFoundError.new
42
44
  end
43
- self.build(body)
45
+ res = self.build(body)
46
+ res.context = context
47
+ res
44
48
  end
45
49
 
46
50
  def find(context, id)
@@ -73,7 +77,7 @@ module Arrest
73
77
  collection = args[0]
74
78
  call_args = args.drop(1)
75
79
  collection.select do |instance|
76
- instance.instance_exec(call_args, &aproc)
80
+ instance.instance_exec(*call_args, &aproc)
77
81
  end
78
82
  end
79
83
  send :define_singleton_method, name do |context, args = nil|
@@ -1,3 +1,3 @@
1
1
  module Arrest
2
- VERSION = "0.0.24"
2
+ VERSION = "0.0.25"
3
3
  end
data/test/unit.rb CHANGED
@@ -610,8 +610,41 @@ class FirstTest < Test::Unit::TestCase
610
610
 
611
611
  def test_update_attribute
612
612
  zoo1 = @scope.Zoo.new(:name => 'zoo1')
613
+ assert zoo1.save
613
614
  zoo1.update_attributes({:name => "updated"})
614
615
  assert_equal "updated", zoo1.name
616
+
617
+ zoo_reloaded = @scope.Zoo.find(zoo1.id)
618
+ assert_equal "updated", zoo_reloaded.name
619
+
620
+ end
621
+
622
+ def test_reload
623
+ zoo1 = @scope.Zoo.new(:name => 'zoo1')
624
+ assert zoo1.save
625
+
626
+ zoo2 = @scope.Zoo.find(zoo1.id)
627
+ assert zoo2.save
628
+
629
+ zoo1.name = "updated"
630
+ assert zoo1.save
631
+
632
+ assert_not_equal zoo1.name, zoo2.name
633
+
634
+ zoo2.reload
635
+
636
+ assert_equal zoo1.name, zoo2.name
637
+ end
638
+
639
+ def test_unset_porperty
640
+ # just taking a class that has a not mandatory attribute
641
+ zo = @scope.ZooOwner.new({ :name => 'meeeee' })
642
+ assert zo.save
643
+
644
+ zo.name = nil
645
+ assert zo.save
646
+
647
+ assert_nil zo.name, "Name should be unset"
615
648
  end
616
649
  end
617
650
 
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.24
4
+ version: 0.0.25
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-02-08 00:00:00.000000000Z
12
+ date: 2012-02-14 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
16
- requirement: &21754080 !ruby/object:Gem::Requirement
16
+ requirement: &2165743640 !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: *21754080
24
+ version_requirements: *2165743640
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: faraday
27
- requirement: &21753220 !ruby/object:Gem::Requirement
27
+ requirement: &2165742880 !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: *21753220
35
+ version_requirements: *2165742880
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: activemodel
38
- requirement: &21752320 !ruby/object:Gem::Requirement
38
+ requirement: &2165742160 !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: *21752320
46
+ version_requirements: *2165742160
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
- requirement: &21751740 !ruby/object:Gem::Requirement
49
+ requirement: &2165741420 !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: *21751740
57
+ version_requirements: *2165741420
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rake
60
- requirement: &21008800 !ruby/object:Gem::Requirement
60
+ requirement: &2165740740 !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: *21008800
68
+ version_requirements: *2165740740
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rdoc
71
- requirement: &21007480 !ruby/object:Gem::Requirement
71
+ requirement: &2165739820 !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: *21007480
79
+ version_requirements: *2165739820
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &21004600 !ruby/object:Gem::Requirement
82
+ requirement: &2165737740 !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: *21004600
90
+ version_requirements: *2165737740
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rr
93
- requirement: &21003160 !ruby/object:Gem::Requirement
93
+ requirement: &2165725320 !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: *21003160
101
+ version_requirements: *2165725320
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: simplecov
104
- requirement: &21002300 !ruby/object:Gem::Requirement
104
+ requirement: &2165723960 !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: *21002300
112
+ version_requirements: *2165723960
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rack
115
- requirement: &20992400 !ruby/object:Gem::Requirement
115
+ requirement: &2165723360 !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: *20992400
123
+ version_requirements: *2165723360
124
124
  description: Consume a rest API in a AR like fashion
125
125
  email:
126
126
  - axel.tetzlaff@fortytools.com
@@ -193,4 +193,13 @@ rubygems_version: 1.8.10
193
193
  signing_key:
194
194
  specification_version: 3
195
195
  summary: Another ruby rest client
196
- test_files: []
196
+ test_files:
197
+ - spec/arrest_spec.rb
198
+ - spec/spec_helper.rb
199
+ - spec/support/models/user.rb
200
+ - test/context.rb
201
+ - test/has_attributed.rb
202
+ - test/models.rb
203
+ - test/nested_resource.rb
204
+ - test/unit.rb
205
+ - test/validations.rb