arrest 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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: