arrest 0.0.1 → 0.0.2

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.
data/arrest.gemspec CHANGED
@@ -20,5 +20,5 @@ Gem::Specification.new do |s|
20
20
 
21
21
  # specify any dependencies here; for example:
22
22
  # s.add_development_dependency "rspec"
23
- # s.add_runtime_dependency "rest-client"
23
+ s.add_runtime_dependency "json"
24
24
  end
data/lib/arrest.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "arrest/version"
2
2
 
3
+ require "arrest/source"
3
4
  require "arrest/http_source"
4
5
  require "arrest/mem_source"
5
6
  require "arrest/abstract_resource"
@@ -8,11 +9,51 @@ require "arrest/rest_child"
8
9
 
9
10
  module Arrest
10
11
 
11
- class Source
12
-
13
- cattr_accessor :source
12
+ String.class_eval do
14
13
 
15
- end
16
- Source.source= MemSource.new
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
17
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
18
59
  end
@@ -1,42 +1,113 @@
1
+ require 'json'
2
+
1
3
  module Arrest
2
4
  class AbstractResource
3
- extend ActiveModel::Naming
4
-
5
- attr_accessor :keys
6
-
7
5
  class << self
8
6
 
7
+ attr_accessor :fields
8
+
9
9
  def source
10
10
  Arrest::Source::source
11
11
  end
12
12
 
13
-
14
13
  def body_root response
15
14
  all = JSON.parse response
16
15
  all["result"]
17
16
  end
18
17
 
19
18
  def build hash
20
- raise "override in subclass with a method, that converts the given hash to an object of the desired class"
19
+ self.new hash
21
20
  end
22
21
 
23
22
  def resource_name
24
- self.name.sub(/.*:/,'').downcase.pluralize
23
+ self.name.sub(/.*:/,'').downcase.plural
24
+ end
25
+
26
+ def has_many(*args)
27
+ method_name, options = args
28
+ method_name = method_name.to_sym
29
+
30
+ clazz_name = method_name.to_s
31
+ if options
32
+ clazz = options[:class_name]
33
+ if clazz
34
+ clazz_name = clazz.to_s
35
+ end
36
+ end
37
+ send :define_method, method_name do
38
+ Arrest::Source.mod.const_get(clazz_name.classify).all_for self
39
+ end
40
+ end
41
+
42
+ def parent(*args)
43
+ method_name = args[0].to_s.to_sym
44
+ send :define_method, method_name do
45
+ self.parent
46
+ end
47
+ end
48
+
49
+ def add_attribute attribute_name
50
+ if @fields == nil
51
+ @fields = []
52
+ end
53
+ @fields << attribute_name
54
+ end
55
+
56
+ def attributes(*args)
57
+ args.each do |arg|
58
+ self.send :attr_accessor,arg
59
+ add_attribute arg
60
+ end
61
+ end
62
+
63
+ def belongs_to(*args)
64
+ arg = args[0]
65
+ name = arg.to_s.downcase
66
+ attributes "#{name}_id".to_sym
67
+ send :define_method, name do
68
+ val = self.instance_variable_get("@#{name}_id")
69
+ Arrest::Source.mod.const_get(name.classify).find(val)
70
+ end
71
+ end
72
+ end
73
+
74
+ attr_accessor :id
75
+
76
+ def initialize as_i
77
+ as = {}
78
+ as_i.each_pair do |k,v|
79
+ as[k.to_sym] = v
80
+ 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])
86
+ end
25
87
  end
88
+ self.id = as[:id]
89
+ end
90
+
91
+ def to_hash
92
+ 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}")
97
+ end
98
+ end
99
+ result[:id] = self.id
100
+ result
101
+
26
102
  end
27
103
 
28
104
  def save
29
- if self.respond_to?(:id) && self.id.present?
105
+ if self.respond_to?(:id) && self.id != nil
30
106
  AbstractResource::source().put self
31
107
  else
32
108
  AbstractResource::source().post self
33
109
  end
34
110
  end
35
111
 
36
-
37
- def to_hash
38
- raise "override symmetrically to build, to create a hash representation from self"
39
- end
40
-
41
112
  end
42
113
  end
@@ -20,13 +20,13 @@ module Arrest
20
20
  end
21
21
 
22
22
  def put rest_resource
23
- raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id.present?
23
+ raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
24
24
  hash = rest_resource.to_hash
25
25
  hash.delete(:id)
26
26
  hash.delete("id")
27
27
 
28
28
  response = self.connection().put do |req|
29
- req.url "#{rest_resource.class.path}/#{rest_resource.id}"
29
+ req.url rest_resource.location
30
30
  add_headers req.headers
31
31
  req.body = hash.to_json
32
32
  end
@@ -35,11 +35,11 @@ module Arrest
35
35
 
36
36
  def post rest_resource
37
37
  raise "new object must have setter for id" unless rest_resource.respond_to?(:id=)
38
- raise "new object must not have id" if rest_resource.respond_to?(:id) && rest_resource.id.present?
38
+ raise "new object must not have id" if rest_resource.respond_to?(:id) && rest_resource.id != nil
39
39
  hash = rest_resource.to_hash
40
40
 
41
41
  response = self.connection().post do |req|
42
- req.url rest_resource.class.path
42
+ req.url rest_resource.class.resource_path
43
43
  add_headers req.headers
44
44
  req.body = hash.to_json
45
45
  end
@@ -16,13 +16,13 @@ module Arrest
16
16
  "{
17
17
  \"queryTime\" : \"0.01866644\",
18
18
  \"resultCount\" : #{count},
19
- \"results\" : #{content} }"
19
+ \"result\" : #{content} }"
20
20
 
21
21
  end
22
22
 
23
23
  def get sub
24
24
  idx = sub.rindex(/\/[0-9]*$/)
25
- if idx.present?
25
+ if idx
26
26
  ps = [sub[0..(idx-1)], sub[(idx+1)..sub.length]]
27
27
  else
28
28
  ps = [sub]
@@ -30,7 +30,7 @@ module Arrest
30
30
  val = traverse @@data,ps
31
31
  if val.is_a?(Hash)
32
32
  wrap collection_json(val.values), val.length
33
- elsif val.blank?
33
+ elsif val == nil
34
34
  wrap "{}", 0
35
35
  else
36
36
  wrap val.to_hash.to_json, 1
@@ -49,7 +49,7 @@ module Arrest
49
49
  return hash
50
50
  end
51
51
  key = keys.first
52
- if hash.blank?
52
+ if hash == nil
53
53
  nil
54
54
  else
55
55
  traverse hash[key.to_s],keys.drop(1)
@@ -59,14 +59,14 @@ module Arrest
59
59
 
60
60
  def put rest_resource
61
61
  @@data[rest_resource.resource_path()][rest_resource.id.to_s] = rest_resource
62
- raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id.present?
62
+ raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
63
63
  rest_resource
64
64
  end
65
65
 
66
66
  def post rest_resource
67
67
  raise "new object must have setter for id" unless rest_resource.respond_to?(:id=)
68
- raise "new object must not have id" if rest_resource.respond_to?(:id) && rest_resource.id.present?
69
- if @@data[rest_resource.resource_path()].present?
68
+ raise "new object must not have id" if rest_resource.respond_to?(:id) && rest_resource.id != nil
69
+ if @@data[rest_resource.resource_path()] != nil
70
70
  last_id = @@data[rest_resource.resource_path()].values.map(&:id).sort.last
71
71
  else
72
72
  last_id = 42
@@ -77,7 +77,7 @@ module Arrest
77
77
  next_id = "#{last_id}x"
78
78
  end
79
79
  rest_resource.id = next_id
80
- unless @@data[rest_resource.resource_path()].present?
80
+ unless @@data[rest_resource.resource_path()] != nil
81
81
  @@data[rest_resource.resource_path()] = {}
82
82
  end
83
83
  @@data[rest_resource.resource_path()][next_id.to_s] = rest_resource
@@ -1,7 +1,8 @@
1
1
  module Arrest
2
2
  class RestChild < AbstractResource
3
3
  attr_accessor :parent
4
- def initialize parent
4
+ def initialize parent, h
5
+ super h
5
6
  @parent = parent
6
7
  end
7
8
 
@@ -11,8 +12,13 @@ module Arrest
11
12
  "#{parent.location}/#{self.resource_name}"
12
13
  end
13
14
 
15
+ def build parent, hash
16
+ self.new parent, hash
17
+ end
18
+
14
19
 
15
20
  def all_for parent
21
+ raise "Parent has no id yet" unless parent.id
16
22
  body_root(source().get self.resource_path_for(parent)).map do |h|
17
23
  self.build(parent, h)
18
24
  end
@@ -8,7 +8,9 @@ module Arrest
8
8
  end
9
9
 
10
10
  def all
11
- body_root(source().get self.resource_path).map do |h|
11
+ body = body_root(source().get self.resource_path)
12
+ body ||= []
13
+ body.map do |h|
12
14
  self.build h
13
15
  end
14
16
  end
@@ -0,0 +1,30 @@
1
+ module Arrest
2
+
3
+ class Source
4
+ class << self
5
+ attr_reader :source
6
+ attr_reader :mod
7
+
8
+ def source=(host=nil)
9
+ if host == nil || host.blank?
10
+ @source = MemSource.new
11
+ else
12
+ @source = HttpSource.new host
13
+ end
14
+ @source
15
+ end
16
+
17
+ def mod=(mod=nil)
18
+ if mod == nil
19
+ @mod = Kernel
20
+ elsif mod.is_a?(Module)
21
+ @mod = mod
22
+ else
23
+ raise "Expected module but got #{mod.class.name}"
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ Source.mod = nil
30
+ end
@@ -1,3 +1,3 @@
1
1
  module Arrest
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/test/unit.rb ADDED
@@ -0,0 +1,127 @@
1
+ require 'arrest'
2
+ require 'test/unit'
3
+
4
+ class Zoo < Arrest::RootResource
5
+
6
+ attributes :name
7
+
8
+ has_many :animals
9
+
10
+ end
11
+
12
+ class Animal < Arrest::RestChild
13
+
14
+ attributes :kind, :age
15
+
16
+ parent :zoo
17
+
18
+ end
19
+
20
+ class FirstTest < Test::Unit::TestCase
21
+
22
+ def setup
23
+ Arrest::Source.source = nil
24
+ end
25
+
26
+ def test_mem_src
27
+ Arrest::Source.source = nil
28
+ src = Arrest::Source.source
29
+ assert_equal Arrest::MemSource, src.class
30
+ end
31
+
32
+ def test_init
33
+ zooname = "Hagenbecks"
34
+ z = Zoo.new({:name => zooname})
35
+ assert_equal zooname, z.name
36
+ end
37
+
38
+ def test_create
39
+ zoo_count_before = Zoo.all.length
40
+ new_zoo = Zoo.new({:name => "Foo"})
41
+ new_zoo.save
42
+ zoo_count_after = Zoo.all.length
43
+
44
+ assert_equal (zoo_count_before + 1), zoo_count_after
45
+ assert new_zoo.id != nil
46
+
47
+ zoo_the_last = Zoo.all.last
48
+ assert_equal new_zoo.name, zoo_the_last.name
49
+
50
+ zoo_reloaded = Zoo.find(new_zoo.id)
51
+ assert_equal new_zoo.name, zoo_reloaded.name
52
+ end
53
+
54
+ def test_create_and_load
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
+ end
62
+
63
+ def test_update
64
+ new_zoo = Zoo.new({:name => "Foo"})
65
+ new_zoo.save
66
+
67
+ new_zoo_name = "Hagenbecks"
68
+ new_zoo.name = new_zoo_name
69
+ new_zoo.save
70
+
71
+ assert new_zoo.id != nil
72
+
73
+ zoo_reloaded = Zoo.find(new_zoo.id)
74
+
75
+ assert_equal new_zoo_name, zoo_reloaded.name
76
+ end
77
+
78
+ def test_child
79
+ new_zoo = Zoo.new({:name => "Foo"})
80
+ new_zoo.save
81
+
82
+ animal_kind = "mouse"
83
+ new_animal = Animal.new new_zoo, {:kind => animal_kind, :age => 42}
84
+ assert new_zoo.id != nil
85
+ assert_equal new_zoo.id, new_animal.zoo.id
86
+ assert_equal new_zoo.id, new_animal.parent.id
87
+
88
+ new_animal.save
89
+
90
+ assert new_animal.id != nil
91
+
92
+ zoo_reloaded = Zoo.find(new_zoo.id)
93
+
94
+
95
+ assert_equal 1, zoo_reloaded.animals.length
96
+ assert_equal 42, zoo_reloaded.animals.first.age
97
+
98
+ animal_reloaded = zoo_reloaded.animals.first
99
+
100
+ assert_equal new_zoo.id, animal_reloaded.zoo.id
101
+
102
+ assert_equal animal_kind, zoo_reloaded.animals.first.kind
103
+ end
104
+
105
+ def test_child_update
106
+ new_zoo = Zoo.new({:name => "Foo"})
107
+ new_zoo.save
108
+
109
+ animal_kind = "mouse"
110
+ new_animal = Animal.new new_zoo, {:kind => "foo", :age => 42}
111
+ new_animal.save
112
+
113
+ animal_reloaded = new_zoo.animals.first
114
+ animal_reloaded.kind = animal_kind
115
+ animal_reloaded.save
116
+
117
+ assert_equal animal_kind, animal_reloaded.kind
118
+
119
+ animal_retry = new_zoo.animals.last
120
+ assert_equal animal_kind, animal_retry.kind
121
+
122
+
123
+
124
+ end
125
+
126
+ end
127
+
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.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,19 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-03 00:00:00.000000000Z
13
- dependencies: []
12
+ date: 2011-11-07 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: &18515300 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *18515300
14
25
  description: Consume a rest API in a AR like fashion
15
26
  email:
16
27
  - axel.tetzlaff@fortytools.com
@@ -29,7 +40,9 @@ files:
29
40
  - lib/arrest/mem_source.rb
30
41
  - lib/arrest/rest_child.rb
31
42
  - lib/arrest/root_resource.rb
43
+ - lib/arrest/source.rb
32
44
  - lib/arrest/version.rb
45
+ - test/unit.rb
33
46
  homepage: ''
34
47
  licenses: []
35
48
  post_install_message: