arrest 0.0.2 → 0.0.3

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.
@@ -21,4 +21,5 @@ Gem::Specification.new do |s|
21
21
  # specify any dependencies here; for example:
22
22
  # s.add_development_dependency "rspec"
23
23
  s.add_runtime_dependency "json"
24
+ s.add_runtime_dependency "faraday", '0.7.5'
24
25
  end
@@ -9,51 +9,4 @@ require "arrest/rest_child"
9
9
 
10
10
  module Arrest
11
11
 
12
- String.class_eval do
13
-
14
- PLURALS = [['(quiz)$', '\1zes'],['(ox)$', '\1en'],['([m|l])ouse$', '\1ice'],['(matr|vert|ind)ix|ex$', '\1ices'],
15
- ['(x|ch|ss|sh)$', '\1es'],['([^aeiouy]|qu)ies$', '\1y'],['([^aeiouy]|q)y$$', '\1ies'],['(hive)$', '\1s'],
16
- ['(?:[^f]fe|([lr])f)$', '\1\2ves'],['(sis)$', 'ses'],['([ti])um$', '\1a'],['(buffal|tomat)o$', '\1oes'],['(bu)s$', '\1es'],
17
- ['(alias|status)$', '\1es'],['(octop|vir)us$', '\1i'],['(ax|test)is$', '\1es'],['s$', 's'],['$', 's']]
18
- SINGULARS =[['(quiz)zes$', '\1'],['(matr)ices$', '\1ix'],['(vert|ind)ices$', '\1ex'],['^(ox)en$', '\1'],['(alias|status)es$', '\1'],
19
- ['(octop|vir)i$', '\1us'],['(cris|ax|test)es$', '\1is'],['(shoe)s$', '\1'],['[o]es$', '\1'],['[bus]es$', '\1'],['([m|l])ice$', '\1ouse'],
20
- ['(x|ch|ss|sh)es$', '\1'],['(m)ovies$', '\1ovie'],['[s]eries$', '\1eries'],['([^aeiouy]|qu)ies$', '\1y'],['[lr]ves$', '\1f'],
21
- ['(tive)s$', '\1'],['(hive)s$', '\1'],['([^f])ves$', '\1fe'],['(^analy)ses$', '\1sis'],
22
- ['([a]naly|[b]a|[d]iagno|[p]arenthe|[p]rogno|[s]ynop|[t]he)ses$', '\1\2sis'],['([ti])a$', '\1um'],['(news)$', '\1ews'], ['(.*)s$', '\1'], ['^(.*)$', '\1']]
23
-
24
- def singular()
25
- SINGULARS.each { |match_exp, replacement_exp| return gsub(Regexp.compile(match_exp), replacement_exp) unless match(Regexp.compile(match_exp)).nil?}
26
- end
27
-
28
- def plural()
29
- PLURALS.each { |match_exp, replacement_exp| return gsub(Regexp.compile(match_exp), replacement_exp) unless match(Regexp.compile(match_exp)).nil? }
30
- end
31
-
32
- def plural?
33
- PLURALS.each {|match_exp, replacement_exp| return true if match(Regexp.compile(match_exp))}
34
- false
35
- end
36
-
37
- def blank?
38
- self == nil || self == ""
39
- end
40
-
41
- def classify(upper_first = true)
42
- result = ""
43
- upperNext = false
44
- self.singular.each_char do |c|
45
- if c == "_"
46
- upperNext = true
47
- else
48
- if upperNext || (result.blank? && upper_first)
49
- result << c.upcase
50
- else
51
- result << c
52
- end
53
- upperNext = false
54
- end
55
- end
56
- result
57
- end
58
- end
59
12
  end
@@ -1,6 +1,10 @@
1
1
  require 'json'
2
+ require 'arrest/string_utils'
2
3
 
3
4
  module Arrest
5
+
6
+ Attribute = Struct.new(:name, :read_only)
7
+
4
8
  class AbstractResource
5
9
  class << self
6
10
 
@@ -11,16 +15,23 @@ module Arrest
11
15
  end
12
16
 
13
17
  def body_root response
18
+ if response == nil
19
+ return nil
20
+ end
14
21
  all = JSON.parse response
15
22
  all["result"]
16
23
  end
17
24
 
18
25
  def build hash
19
- self.new hash
26
+ underscored_hash = {}
27
+ hash.each_pair do |k, v|
28
+ underscored_hash[StringUtils.underscore k] = v
29
+ end
30
+ self.new underscored_hash
20
31
  end
21
32
 
22
33
  def resource_name
23
- self.name.sub(/.*:/,'').downcase.plural
34
+ StringUtils.plural self.name.sub(/.*:/,'').downcase
24
35
  end
25
36
 
26
37
  def has_many(*args)
@@ -35,7 +46,7 @@ module Arrest
35
46
  end
36
47
  end
37
48
  send :define_method, method_name do
38
- Arrest::Source.mod.const_get(clazz_name.classify).all_for self
49
+ Arrest::Source.mod.const_get(StringUtils.classify clazz_name).all_for self
39
50
  end
40
51
  end
41
52
 
@@ -46,17 +57,33 @@ module Arrest
46
57
  end
47
58
  end
48
59
 
49
- def add_attribute attribute_name
60
+ def add_attribute attribute
50
61
  if @fields == nil
51
62
  @fields = []
52
63
  end
53
- @fields << attribute_name
64
+ @fields << attribute
65
+ end
66
+
67
+ def all_fields
68
+ if self.superclass.respond_to?('fields') && self.superclass.fields != nil
69
+ self.fields + self.superclass.fields
70
+ else
71
+ self.fields
72
+ end
73
+
74
+ end
75
+
76
+ def read_only_attributes(*args)
77
+ args.each do |arg|
78
+ self.send :attr_accessor,arg
79
+ add_attribute Attribute.new(arg, true)
80
+ end
54
81
  end
55
82
 
56
83
  def attributes(*args)
57
84
  args.each do |arg|
58
85
  self.send :attr_accessor,arg
59
- add_attribute arg
86
+ add_attribute Attribute.new(arg, false)
60
87
  end
61
88
  end
62
89
 
@@ -66,7 +93,7 @@ module Arrest
66
93
  attributes "#{name}_id".to_sym
67
94
  send :define_method, name do
68
95
  val = self.instance_variable_get("@#{name}_id")
69
- Arrest::Source.mod.const_get(name.classify).find(val)
96
+ Arrest::Source.mod.const_get(StringUtils.classify name).find(val)
70
97
  end
71
98
  end
72
99
  end
@@ -78,11 +105,9 @@ module Arrest
78
105
  as_i.each_pair do |k,v|
79
106
  as[k.to_sym] = v
80
107
  end
81
- unless self.class.fields == nil
82
- self.class.fields.each do |field|
83
- json_name = field.to_s.classify(false)
84
- json_name[0] = json_name[0].downcase
85
- self.instance_variable_set("@#{field.to_s}", as[json_name.to_sym])
108
+ unless self.class.all_fields == nil
109
+ self.class.all_fields.each do |field|
110
+ self.send("#{field.name.to_s}=", as[field.name.to_sym])
86
111
  end
87
112
  end
88
113
  self.id = as[:id]
@@ -90,10 +115,10 @@ module Arrest
90
115
 
91
116
  def to_hash
92
117
  result = {}
93
- unless self.class.fields == nil
94
- self.class.fields.each do |field|
95
- json_name = field.to_s.classify(false)
96
- result[json_name] = self.instance_variable_get("@#{field.to_s}")
118
+ unless self.class.all_fields == nil
119
+ self.class.all_fields.find_all{|a| !a.read_only}.each do |field|
120
+ json_name = StringUtils.classify(field.name.to_s,false)
121
+ result[json_name] = self.instance_variable_get("@#{field.name.to_s}")
97
122
  end
98
123
  end
99
124
  result[:id] = self.id
@@ -109,5 +134,9 @@ module Arrest
109
134
  end
110
135
  end
111
136
 
137
+ def delete
138
+ AbstractResource::source().delete self
139
+ end
140
+
112
141
  end
113
142
  end
@@ -1,3 +1,5 @@
1
+ require 'faraday'
2
+
1
3
  module Arrest
2
4
  class HttpSource
3
5
 
@@ -6,9 +8,9 @@ module Arrest
6
8
  end
7
9
 
8
10
  def add_headers headers
9
- puts "FOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
10
- headers['X-SplinkUser'] = '0'
11
- headers['Content-Type'] = 'application/json'
11
+ Arrest::Source.header_decorator.headers.each_pair do |k,v|
12
+ headers[k.to_s] = v.to_s
13
+ end
12
14
  end
13
15
 
14
16
  def get sub
@@ -19,6 +21,15 @@ module Arrest
19
21
  response.body
20
22
  end
21
23
 
24
+ def delete rest_resource
25
+ raise "To delete an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
26
+ response = self.connection().delete do |req|
27
+ req.url rest_resource.location
28
+ add_headers req.headers
29
+ end
30
+ response.env[:status] == 200
31
+ end
32
+
22
33
  def put rest_resource
23
34
  raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
24
35
  hash = rest_resource.to_hash
@@ -37,16 +48,28 @@ module Arrest
37
48
  raise "new object must have setter for id" unless rest_resource.respond_to?(:id=)
38
49
  raise "new object must not have id" if rest_resource.respond_to?(:id) && rest_resource.id != nil
39
50
  hash = rest_resource.to_hash
51
+ hash.delete(:id)
52
+ hash.delete('id')
53
+
54
+ hash.delete_if{|k,v| v == nil}
40
55
 
56
+ puts "URL:#{rest_resource.class.resource_path}"
57
+ body = hash.to_json
58
+ puts "Body:#{body}"
41
59
  response = self.connection().post do |req|
42
60
  req.url rest_resource.class.resource_path
43
61
  add_headers req.headers
44
- req.body = hash.to_json
62
+ req.body = body
63
+ end
64
+ if (response.env[:status] == 201)
65
+ location = response.env[:response_headers][:location]
66
+ id = location.gsub(/^.*\//, '')
67
+ rest_resource.id= id
68
+ else
69
+ puts "unable to create: #{response.env[:response_headers]} body: #{response.body} "
70
+ false
45
71
  end
46
- location = response.env[:response_headers][:location]
47
- id = location.gsub(/^.*\//, '')
48
- rest_resource.id= id
49
- response.env[:status] == 201
72
+
50
73
  end
51
74
 
52
75
  def connection
@@ -57,9 +57,15 @@ module Arrest
57
57
  end
58
58
 
59
59
 
60
+ def delete rest_resource
61
+ raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
62
+ @@data[rest_resource.resource_path()].delete(rest_resource.id.to_s)
63
+ rest_resource
64
+ end
65
+
60
66
  def put rest_resource
61
- @@data[rest_resource.resource_path()][rest_resource.id.to_s] = rest_resource
62
67
  raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
68
+ @@data[rest_resource.resource_path()][rest_resource.id.to_s] = rest_resource
63
69
  rest_resource
64
70
  end
65
71
 
@@ -4,6 +4,7 @@ module Arrest
4
4
  class << self
5
5
  attr_reader :source
6
6
  attr_reader :mod
7
+ attr_reader :header_decorator
7
8
 
8
9
  def source=(host=nil)
9
10
  if host == nil || host.blank?
@@ -24,7 +25,23 @@ module Arrest
24
25
  end
25
26
  end
26
27
 
28
+ def header_decorator=(hd=nil)
29
+ puts "Setting headerd to #{hd}"
30
+ if hd == nil
31
+ @header_decorator = self
32
+ elsif hd.respond_to?(:headers)
33
+ @header_decorator = hd
34
+ else
35
+ raise "Header_decorator must be an object that returns an hash for the method headers"
36
+ end
37
+ end
38
+
39
+ def headers
40
+ {}
41
+ end
42
+
27
43
  end
28
44
  end
29
45
  Source.mod = nil
46
+ Source.header_decorator = Source
30
47
  end
@@ -0,0 +1,63 @@
1
+ class StringUtils
2
+ class << self
3
+
4
+ PLURALS = [['(quiz)$', '\1zes'],['(ox)$', '\1en'],['([m|l])ouse$', '\1ice'],['(matr|vert|ind)ix|ex$', '\1ices'],
5
+ ['(x|ch|ss|sh)$', '\1es'],['([^aeiouy]|qu)ies$', '\1y'],['([^aeiouy]|q)y$$', '\1ies'],['(hive)$', '\1s'],
6
+ ['(?:[^f]fe|([lr])f)$', '\1\2ves'],['(sis)$', 'ses'],['([ti])um$', '\1a'],['(buffal|tomat)o$', '\1oes'],['(bu)s$', '\1es'],
7
+ ['(alias|status)$', '\1es'],['(octop|vir)us$', '\1i'],['(ax|test)is$', '\1es'],['s$', 's'],['$', 's']]
8
+ SINGULARS =[['(quiz)zes$', '\1'],['(matr)ices$', '\1ix'],['(vert|ind)ices$', '\1ex'],['^(ox)en$', '\1'],['(alias|status)es$', '\1'],
9
+ ['(octop|vir)i$', '\1us'],['(cris|ax|test)es$', '\1is'],['(shoe)s$', '\1'],['[o]es$', '\1'],['[bus]es$', '\1'],['([m|l])ice$', '\1ouse'],
10
+ ['(x|ch|ss|sh)es$', '\1'],['(m)ovies$', '\1ovie'],['[s]eries$', '\1eries'],['([^aeiouy]|qu)ies$', '\1y'],['[lr]ves$', '\1f'],
11
+ ['(tive)s$', '\1'],['(hive)s$', '\1'],['([^f])ves$', '\1fe'],['(^analy)ses$', '\1sis'],
12
+ ['([a]naly|[b]a|[d]iagno|[p]arenthe|[p]rogno|[s]ynop|[t]he)ses$', '\1\2sis'],['([ti])a$', '\1um'],['(news)$', '\1ews'], ['(.*)s$', '\1'], ['^(.*)$', '\1']]
13
+
14
+ def singular(str)
15
+ SINGULARS.each { |match_exp, replacement_exp| return str.gsub(Regexp.compile(match_exp), replacement_exp) unless str.match(Regexp.compile(match_exp)).nil?}
16
+ end
17
+
18
+ def plural(str)
19
+ PLURALS.each { |match_exp, replacement_exp| return str.gsub(Regexp.compile(match_exp), replacement_exp) unless str.match(Regexp.compile(match_exp)).nil? }
20
+ end
21
+
22
+ def plural?
23
+ PLURALS.each {|match_exp, replacement_exp| return true if str.match(Regexp.compile(match_exp))}
24
+ false
25
+ end
26
+
27
+ def blank? str
28
+ str == nil || str == ""
29
+ end
30
+
31
+ def is_upper? str
32
+ str == str.upcase
33
+ end
34
+
35
+ def underscore str
36
+ word = str.to_s.dup
37
+ word.gsub!(/::/, '/')
38
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
39
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
40
+ word.tr!("-", "_")
41
+ word.downcase!
42
+ word
43
+ end
44
+
45
+ def classify(str, upper_first = true)
46
+ result = ""
47
+ upperNext = false
48
+ (singular str) .each_char do |c|
49
+ if c == "_"
50
+ upperNext = true
51
+ else
52
+ if upperNext || (result == "" && upper_first)
53
+ result << c.upcase
54
+ else
55
+ result << c
56
+ end
57
+ upperNext = false
58
+ end
59
+ end
60
+ result
61
+ end
62
+ end
63
+ end
@@ -1,3 +1,3 @@
1
1
  module Arrest
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -2,19 +2,19 @@ require 'arrest'
2
2
  require 'test/unit'
3
3
 
4
4
  class Zoo < Arrest::RootResource
5
-
6
5
  attributes :name
7
-
6
+ read_only_attributes :ro1
8
7
  has_many :animals
9
-
10
8
  end
11
9
 
12
10
  class Animal < Arrest::RestChild
13
-
14
11
  attributes :kind, :age
15
-
16
12
  parent :zoo
13
+ end
17
14
 
15
+ class SpecialZoo < Zoo
16
+ read_only_attributes :ro2
17
+ attributes :is_magic
18
18
  end
19
19
 
20
20
  class FirstTest < Test::Unit::TestCase
@@ -51,6 +51,25 @@ class FirstTest < Test::Unit::TestCase
51
51
  assert_equal new_zoo.name, zoo_reloaded.name
52
52
  end
53
53
 
54
+ def test_delete
55
+ zoo_count_before = Zoo.all.length
56
+ new_zoo = Zoo.new({:name => "Foo"})
57
+ new_zoo.save
58
+ zoo_count_after = Zoo.all.length
59
+
60
+ assert_equal (zoo_count_before + 1), zoo_count_after
61
+ assert new_zoo.id != nil
62
+
63
+ zoo_the_last = Zoo.all.last
64
+ assert_equal new_zoo.name, zoo_the_last.name
65
+
66
+ zoo_reloaded = Zoo.find(new_zoo.id)
67
+ assert_equal new_zoo.name, zoo_reloaded.name
68
+
69
+ zoo_reloaded.delete
70
+ assert_equal zoo_count_before, Zoo.all.length
71
+ end
72
+
54
73
  def test_create_and_load
55
74
  zoo_count_before = Zoo.all.length
56
75
  new_zoo = Zoo.new({:name => "Foo"})
@@ -118,10 +137,49 @@ class FirstTest < Test::Unit::TestCase
118
137
 
119
138
  animal_retry = new_zoo.animals.last
120
139
  assert_equal animal_kind, animal_retry.kind
140
+ end
121
141
 
142
+ def test_inheritance
143
+ new_zoo = SpecialZoo.new({:name => "Foo", :is_magic => true})
144
+ new_zoo.save
122
145
 
146
+ assert new_zoo.id != nil, "Zoo must have id after save"
147
+ zoo_reloaded = SpecialZoo.find(new_zoo.id)
148
+ assert_equal true, zoo_reloaded.is_magic
149
+ assert_equal "Foo", zoo_reloaded.name
150
+ end
151
+
152
+ def test_inheritance_update
153
+ new_zoo = SpecialZoo.new({:name => "Foo", :is_magic => true})
154
+ new_zoo.save
155
+
156
+ assert new_zoo.id != nil, "Zoo must have id after save"
157
+ zoo_reloaded = SpecialZoo.find(new_zoo.id)
158
+ assert_equal true, zoo_reloaded.is_magic
159
+ assert_equal "Foo", zoo_reloaded.name
123
160
 
161
+ new_name = "Bar"
162
+ zoo_reloaded.name = new_name
163
+ zoo_reloaded.is_magic = !zoo_reloaded.is_magic
164
+ zoo_reloaded.save
165
+
166
+ updated_zoo = SpecialZoo.find(zoo_reloaded.id)
167
+ assert_equal new_name, updated_zoo.name
168
+ assert_equal !new_zoo.is_magic, updated_zoo.is_magic
124
169
  end
125
170
 
171
+ def test_read_only_attributes
172
+ zoo = SpecialZoo.new({:name => "Zoo", :ro1 => "one", :ro2 => "two", :is_magic => true})
173
+
174
+ assert_equal "Zoo", zoo.name
175
+ assert_equal "one", zoo.ro1
176
+ assert_equal "two", zoo.ro2
177
+ assert_equal true, zoo.is_magic
178
+
179
+ hash = zoo.to_hash
180
+
181
+ assert_nil hash[:ro1]
182
+ assert_nil hash[:ro2]
183
+ end
126
184
  end
127
185
 
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.2
4
+ version: 0.0.3
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-07 00:00:00.000000000Z
12
+ date: 2011-11-09 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
16
- requirement: &18515300 !ruby/object:Gem::Requirement
16
+ requirement: &2161032680 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,18 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *18515300
24
+ version_requirements: *2161032680
25
+ - !ruby/object:Gem::Dependency
26
+ name: faraday
27
+ requirement: &2161031520 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - =
31
+ - !ruby/object:Gem::Version
32
+ version: 0.7.5
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2161031520
25
36
  description: Consume a rest API in a AR like fashion
26
37
  email:
27
38
  - axel.tetzlaff@fortytools.com
@@ -41,6 +52,7 @@ files:
41
52
  - lib/arrest/rest_child.rb
42
53
  - lib/arrest/root_resource.rb
43
54
  - lib/arrest/source.rb
55
+ - lib/arrest/string_utils.rb
44
56
  - lib/arrest/version.rb
45
57
  - test/unit.rb
46
58
  homepage: ''
@@ -67,4 +79,5 @@ rubygems_version: 1.8.10
67
79
  signing_key:
68
80
  specification_version: 3
69
81
  summary: Another ruby rest client
70
- test_files: []
82
+ test_files:
83
+ - test/unit.rb