arrest 0.0.9 → 0.0.11
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/.gitignore +1 -0
- data/lib/arrest.rb +9 -2
- data/lib/arrest/abstract_resource.rb +36 -2
- data/lib/arrest/attributes/belongs_to.rb +3 -1
- data/lib/arrest/attributes/converter.rb +4 -0
- data/lib/arrest/helper/filter.rb +13 -0
- data/lib/arrest/helper/has_many_collection.rb +56 -0
- data/lib/arrest/helper/logger.rb +8 -0
- data/lib/arrest/http_source.rb +7 -2
- data/lib/arrest/mem_source.rb +4 -0
- data/lib/arrest/rest_child.rb +6 -2
- data/lib/arrest/root_resource.rb +45 -2
- data/lib/arrest/source.rb +2 -0
- data/lib/arrest/validations/inclusion_of.rb +25 -0
- data/lib/arrest/validations/presence_of.rb +18 -0
- data/lib/arrest/validations/validatable.rb +69 -0
- data/lib/arrest/validations/validator.rb +27 -0
- data/lib/arrest/version.rb +1 -1
- data/test/models.rb +15 -2
- data/test/unit.rb +94 -0
- data/test/validations.rb +154 -0
- metadata +30 -22
data/.gitignore
CHANGED
data/lib/arrest.rb
CHANGED
@@ -1,18 +1,25 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
1
3
|
require "arrest/version"
|
4
|
+
require 'arrest/helper/logger'
|
2
5
|
|
3
6
|
require "arrest/attributes/belongs_to"
|
4
7
|
require "arrest/attributes/has_attributes"
|
5
8
|
require "arrest/attributes/converter"
|
6
9
|
require "arrest/source"
|
10
|
+
require "arrest/helper/filter"
|
7
11
|
require "arrest/helper/child_collection"
|
12
|
+
require "arrest/helper/has_many_collection"
|
8
13
|
require "arrest/exceptions"
|
9
14
|
require "arrest/http_source"
|
10
15
|
require "arrest/mem_source"
|
11
16
|
require "arrest/source"
|
12
17
|
require "arrest/nested_resource"
|
18
|
+
require "arrest/validations/validator"
|
19
|
+
require "arrest/validations/presence_of"
|
20
|
+
require "arrest/validations/inclusion_of"
|
21
|
+
require "arrest/validations/validatable"
|
13
22
|
require "arrest/abstract_resource"
|
14
23
|
require "arrest/root_resource"
|
15
24
|
require "arrest/rest_child"
|
16
25
|
|
17
|
-
module Arrest
|
18
|
-
end
|
@@ -9,7 +9,11 @@ module Arrest
|
|
9
9
|
class AbstractResource
|
10
10
|
extend ActiveModel::Naming
|
11
11
|
include HasAttributes
|
12
|
+
include Validatable
|
12
13
|
attribute :id, String
|
14
|
+
|
15
|
+
attr_accessor :errors
|
16
|
+
|
13
17
|
class << self
|
14
18
|
attr_reader :scopes
|
15
19
|
|
@@ -46,6 +50,31 @@ module Arrest
|
|
46
50
|
end
|
47
51
|
|
48
52
|
def has_many(*args)
|
53
|
+
method_name, options = args
|
54
|
+
singular = (StringUtils.singular(method_name.to_s) + '_ids').to_sym
|
55
|
+
method_name = method_name.to_sym
|
56
|
+
|
57
|
+
clazz_name = method_name.to_s
|
58
|
+
if options
|
59
|
+
clazz = options[:class_name]
|
60
|
+
if clazz
|
61
|
+
clazz_name = clazz.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
attribute singular, Array
|
65
|
+
send :define_method, method_name do
|
66
|
+
if @has_many_collections == nil
|
67
|
+
@has_many_collections = {}
|
68
|
+
end
|
69
|
+
if @has_many_collections[method_name] == nil
|
70
|
+
@has_many_collections[method_name] = HasManyCollection.new(self, (StringUtils.classify (StringUtils.singular clazz_name)))
|
71
|
+
end
|
72
|
+
|
73
|
+
@has_many_collections[method_name]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def children(*args)
|
49
78
|
method_name, options = args
|
50
79
|
method_name = method_name.to_sym
|
51
80
|
|
@@ -100,8 +129,13 @@ module Arrest
|
|
100
129
|
end
|
101
130
|
|
102
131
|
def save
|
103
|
-
|
104
|
-
|
132
|
+
self.errors = self.validate
|
133
|
+
if self.errors.empty?
|
134
|
+
verb = new_record? ? :post : :put
|
135
|
+
!!AbstractResource::source.send(verb, self)
|
136
|
+
else
|
137
|
+
false
|
138
|
+
end
|
105
139
|
end
|
106
140
|
|
107
141
|
def new_record?
|
@@ -18,10 +18,12 @@ module Arrest
|
|
18
18
|
class_name = params[:class_name].to_s unless params[:class_name] == nil
|
19
19
|
read_only = params[:read_only] == true
|
20
20
|
end
|
21
|
-
attributes({field_name.to_sym => String})
|
22
21
|
add_attribute(Attribute.new(field_name.to_sym, read_only, String))
|
23
22
|
send :define_method, name do
|
24
23
|
val = self.send(field_name)
|
24
|
+
if val == nil || val == ""
|
25
|
+
return nil
|
26
|
+
end
|
25
27
|
begin
|
26
28
|
Arrest::Source.mod.const_get(class_name).find(val)
|
27
29
|
rescue Errors::DocumentNotFoundError => e
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Arrest
|
2
|
+
# A filter is a named predicate to limit a collection to a subset with
|
3
|
+
# certain features
|
4
|
+
class Filter
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :block
|
7
|
+
|
8
|
+
def initialize name, block = nil
|
9
|
+
@name = name
|
10
|
+
@block = block
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Arrest
|
2
|
+
class HasManyCollection #< BasicObject
|
3
|
+
def initialize parent, clazz_name
|
4
|
+
@parent = parent
|
5
|
+
@clazz_name = clazz_name
|
6
|
+
@children = nil
|
7
|
+
@foreign_key_name = (StringUtils.underscore(@parent.class.name).gsub(/^.*\//, '') + '_id').to_sym
|
8
|
+
define_filters
|
9
|
+
end
|
10
|
+
|
11
|
+
def build attributes = {}
|
12
|
+
extended_attrs = attributes.merge({@foreign_key_name => @parent.id})
|
13
|
+
resolved_class.new extended_attrs
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(*args, &block)
|
17
|
+
children.send(*args, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
children.inspect
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
|
27
|
+
def children
|
28
|
+
if @children == nil
|
29
|
+
url = @parent.resource_location + '/' + resolved_class.resource_name.to_s
|
30
|
+
@children = resolved_class.by_url(url)
|
31
|
+
end
|
32
|
+
@children
|
33
|
+
end
|
34
|
+
|
35
|
+
def resolved_class
|
36
|
+
if @clazz == nil
|
37
|
+
@clazz = Source.mod.const_get(@clazz_name)
|
38
|
+
end
|
39
|
+
@clazz
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def define_filters
|
44
|
+
resolved_class.all_filters.each do |filter|
|
45
|
+
self.instance_eval <<-"end_eval"
|
46
|
+
def #{filter.name} *args
|
47
|
+
real_args = [children] + args
|
48
|
+
#{resolved_class.name}.FILTER_#{filter.name}(real_args)
|
49
|
+
end
|
50
|
+
end_eval
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
data/lib/arrest/http_source.rb
CHANGED
@@ -29,7 +29,11 @@ module Arrest
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def get_many sub, filter={}
|
32
|
-
|
32
|
+
response = self.connection().get do |req|
|
33
|
+
req.url sub, filter
|
34
|
+
add_headers req.headers
|
35
|
+
end
|
36
|
+
response.body
|
33
37
|
end
|
34
38
|
|
35
39
|
def delete rest_resource
|
@@ -43,7 +47,7 @@ module Arrest
|
|
43
47
|
|
44
48
|
def put rest_resource
|
45
49
|
raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id != nil
|
46
|
-
hash = rest_resource.
|
50
|
+
hash = rest_resource.to_jhash
|
47
51
|
hash.delete(:id)
|
48
52
|
hash.delete("id")
|
49
53
|
|
@@ -88,6 +92,7 @@ module Arrest
|
|
88
92
|
builder.request :json
|
89
93
|
builder.response :logger
|
90
94
|
builder.adapter :net_http
|
95
|
+
builder.use Faraday::Response::Logger, Arrest::logger
|
91
96
|
end
|
92
97
|
end
|
93
98
|
|
data/lib/arrest/mem_source.rb
CHANGED
data/lib/arrest/rest_child.rb
CHANGED
@@ -23,8 +23,12 @@ module Arrest
|
|
23
23
|
|
24
24
|
def all_for parent
|
25
25
|
raise "Parent has no id yet" unless parent.id
|
26
|
-
|
27
|
-
self.
|
26
|
+
begin
|
27
|
+
body_root(source().get_many self.resource_path_for(parent)).map do |h|
|
28
|
+
self.build(parent, h)
|
29
|
+
end
|
30
|
+
rescue Arrest::Errors::DocumentNotFoundError
|
31
|
+
[]
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
data/lib/arrest/root_resource.rb
CHANGED
@@ -7,8 +7,26 @@ module Arrest
|
|
7
7
|
"#{self.resource_name}"
|
8
8
|
end
|
9
9
|
|
10
|
+
def by_url url
|
11
|
+
begin
|
12
|
+
body = body_root(source().get_many url)
|
13
|
+
rescue Arrest::Errors::DocumentNotFoundError
|
14
|
+
Arrest::logger.info "DocumentNotFoundError for #{url} gracefully returning []"
|
15
|
+
return []
|
16
|
+
end
|
17
|
+
body ||= []
|
18
|
+
body.map do |h|
|
19
|
+
self.build h
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
10
23
|
def all filter={}
|
11
|
-
|
24
|
+
begin
|
25
|
+
body = body_root(source().get_many self.resource_path, filter)
|
26
|
+
rescue Arrest::Errors::DocumentNotFoundError
|
27
|
+
Arrest::logger.info "DocumentNotFoundError for #{self.resource_path} gracefully returning []"
|
28
|
+
return []
|
29
|
+
end
|
12
30
|
body ||= []
|
13
31
|
body.map do |h|
|
14
32
|
self.build h
|
@@ -19,6 +37,7 @@ module Arrest
|
|
19
37
|
r = source().get_one "#{self.resource_path}/#{id}"
|
20
38
|
body = body_root(r)
|
21
39
|
if body == nil || body.empty?
|
40
|
+
Arrest::logger.info "DocumentNotFoundError for #{self.resource_path}/#{id}"
|
22
41
|
raise Errors::DocumentNotFoundError.new
|
23
42
|
end
|
24
43
|
self.build body.merge({:id => id})
|
@@ -26,7 +45,18 @@ module Arrest
|
|
26
45
|
|
27
46
|
def filter name, &aproc
|
28
47
|
if aproc != nil
|
29
|
-
|
48
|
+
if @filters == nil
|
49
|
+
@filters = []
|
50
|
+
end
|
51
|
+
@filters << Filter.new(name, &aproc)
|
52
|
+
send :define_singleton_method, "FILTER_#{name}" do |args = nil|
|
53
|
+
collection = args[0]
|
54
|
+
call_args = args.drop(1)
|
55
|
+
collection.select do |instance|
|
56
|
+
instance.instance_exec(call_args, &aproc)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
send :define_singleton_method, name do |args = nil|
|
30
60
|
self.all.select do |instance|
|
31
61
|
instance.instance_exec(args, &aproc)
|
32
62
|
end
|
@@ -36,6 +66,19 @@ module Arrest
|
|
36
66
|
end
|
37
67
|
end
|
38
68
|
|
69
|
+
def filters
|
70
|
+
@filters
|
71
|
+
end
|
72
|
+
|
73
|
+
def all_filters
|
74
|
+
all_filters = @filters
|
75
|
+
all_filters ||= []
|
76
|
+
if superclass.respond_to?('filters') && superclass.filters
|
77
|
+
all_fields += superclass.filters
|
78
|
+
end
|
79
|
+
all_filters
|
80
|
+
end
|
81
|
+
|
39
82
|
def scope name, &block
|
40
83
|
super(name)
|
41
84
|
if block_given?
|
data/lib/arrest/source.rb
CHANGED
@@ -16,8 +16,10 @@ module Arrest
|
|
16
16
|
def source=(host=nil)
|
17
17
|
if host == nil || host.blank?
|
18
18
|
@source = MemSource.new
|
19
|
+
Arrest::logger.info "Setting Arrest host empty in-memory-store"
|
19
20
|
else
|
20
21
|
@source = HttpSource.new host
|
22
|
+
Arrest::logger.info "Setting Arrest host to #{host}"
|
21
23
|
end
|
22
24
|
@source
|
23
25
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Arrest
|
2
|
+
module Validations
|
3
|
+
class InclusionOf < Validator
|
4
|
+
|
5
|
+
def initialize attribute, hash
|
6
|
+
super attribute
|
7
|
+
@hash = hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate input
|
11
|
+
errors = []
|
12
|
+
if !input.respond_to?(@attribute)
|
13
|
+
errors << ValidationError.new(@attribute, "not_responding")
|
14
|
+
else
|
15
|
+
val = input.send(@attribute)
|
16
|
+
unless @hash[:in] != nil && @hash[:in].include?(val)
|
17
|
+
errors << ValidationError.new(@attribute,"not_included")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
return errors
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Arrest
|
2
|
+
module Validations
|
3
|
+
class PresenceOf < Validator
|
4
|
+
def validate input
|
5
|
+
errors = []
|
6
|
+
if !input.respond_to?(@attribute)
|
7
|
+
errors << ValidationError.new(@attribute, "not_responding")
|
8
|
+
else
|
9
|
+
val = input.send(@attribute)
|
10
|
+
if val == nil || val == ''
|
11
|
+
errors << ValidationError.new(@attribute,"not_present")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
return errors
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Arrest
|
2
|
+
module Validations
|
3
|
+
class MethodValidator
|
4
|
+
def initialize method = nil, &blk
|
5
|
+
@method = method
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate input
|
9
|
+
input.send(@method)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Validatable
|
15
|
+
def self.included(base) # :nodoc:
|
16
|
+
base.extend ValidatableMethods
|
17
|
+
end
|
18
|
+
|
19
|
+
module ValidatableMethods
|
20
|
+
def validates_presence_of attribute
|
21
|
+
add_validator Validations::PresenceOf.new attribute
|
22
|
+
end
|
23
|
+
|
24
|
+
def validates method_name
|
25
|
+
add_validator Validations::MethodValidator.new method_name
|
26
|
+
end
|
27
|
+
|
28
|
+
def validates_inclusion_of attribute, hash = {}
|
29
|
+
add_validator Validations::InclusionOf.new attribute, hash
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_validator v
|
33
|
+
if @validations == nil
|
34
|
+
@validations = []
|
35
|
+
end
|
36
|
+
@validations << v
|
37
|
+
end
|
38
|
+
|
39
|
+
def validations
|
40
|
+
if self.superclass.respond_to? :validations
|
41
|
+
super_v = self.superclass.validations
|
42
|
+
else
|
43
|
+
super_v = []
|
44
|
+
end
|
45
|
+
if @validations == nil
|
46
|
+
@validations = []
|
47
|
+
end
|
48
|
+
|
49
|
+
@validations + super_v
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# --------- instance methods ---------
|
54
|
+
def valid?
|
55
|
+
validate.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def validate
|
60
|
+
vs = self.class.validations
|
61
|
+
return [] if vs == nil
|
62
|
+
errors = []
|
63
|
+
vs.each do |v|
|
64
|
+
errors += v.validate self
|
65
|
+
end
|
66
|
+
errors
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Arrest
|
2
|
+
module Validations
|
3
|
+
class ValidationError
|
4
|
+
attr_accessor :attribute, :message
|
5
|
+
|
6
|
+
def initialize attribute, message
|
7
|
+
@attribute = attribute
|
8
|
+
@message = message
|
9
|
+
end
|
10
|
+
|
11
|
+
def translate
|
12
|
+
"#{self.attribute} - #{self.message}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Validator
|
17
|
+
def initialize attribute
|
18
|
+
@attribute = attribute
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate input
|
22
|
+
return []
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/arrest/version.rb
CHANGED
data/test/models.rb
CHANGED
@@ -3,10 +3,15 @@ require 'arrest'
|
|
3
3
|
class Zoo < Arrest::RootResource
|
4
4
|
attributes({ :name => String , :open => Boolean})
|
5
5
|
read_only_attributes({ :ro1 => String})
|
6
|
-
|
6
|
+
children :animals
|
7
7
|
|
8
8
|
scope :server_scope
|
9
9
|
scope(:open) { |z| z.open }
|
10
|
+
filter(:open_filter) { open }
|
11
|
+
|
12
|
+
validates_presence_of :name
|
13
|
+
|
14
|
+
belongs_to :zoo_owner
|
10
15
|
end
|
11
16
|
|
12
17
|
class Animal < Arrest::RestChild
|
@@ -20,6 +25,12 @@ class Animal < Arrest::RestChild
|
|
20
25
|
scope(:males_only){|a| a.male}
|
21
26
|
end
|
22
27
|
|
28
|
+
class ZooOwner < Arrest::RootResource
|
29
|
+
attribute :name, String
|
30
|
+
has_many :zoos
|
31
|
+
end
|
32
|
+
|
33
|
+
|
23
34
|
class SpecialZoo < Zoo
|
24
35
|
custom_resource_name :zoo3000
|
25
36
|
read_only_attributes({ :ro2 => String})
|
@@ -73,7 +84,9 @@ class ParentFilter < Arrest::RootResource
|
|
73
84
|
attribute :afield, String
|
74
85
|
|
75
86
|
filter(:nnn) {|s| afield == s}
|
76
|
-
|
87
|
+
filter(:no_param){ afield == "Foo"}
|
88
|
+
filter(:running){ afield == "Foo"}
|
89
|
+
children :child_filters
|
77
90
|
end
|
78
91
|
|
79
92
|
class ChildFilter < Arrest::RestChild
|
data/test/unit.rb
CHANGED
@@ -42,6 +42,35 @@ class FirstTest < Test::Unit::TestCase
|
|
42
42
|
assert_equal new_zoo.id, zoo_reloaded.id
|
43
43
|
end
|
44
44
|
|
45
|
+
def test_prsnc_valid
|
46
|
+
invalid_params = [
|
47
|
+
{},
|
48
|
+
{:name => nil},
|
49
|
+
{:name => ''}
|
50
|
+
]
|
51
|
+
|
52
|
+
invalid_params.each do |p|
|
53
|
+
zoo_count_before = Zoo.all.length
|
54
|
+
new_zoo = Zoo.new(p)
|
55
|
+
assert_equal false, new_zoo.save, "zoo without name shouldnt be persistable"
|
56
|
+
assert_equal zoo_count_before, Zoo.all.length
|
57
|
+
assert_equal :name, new_zoo.errors.first.attribute
|
58
|
+
assert_nil new_zoo.id
|
59
|
+
|
60
|
+
new_zoo.name = "Foo"
|
61
|
+
|
62
|
+
assert new_zoo.save, "Creating should be possible after setting a name"
|
63
|
+
zoo_count_after = Zoo.all.length
|
64
|
+
assert_not_nil new_zoo.id
|
65
|
+
|
66
|
+
assert_equal (zoo_count_before + 1), zoo_count_after
|
67
|
+
assert new_zoo.id != nil
|
68
|
+
|
69
|
+
new_zoo.name = ""
|
70
|
+
assert_equal false, new_zoo.save, "Shouldnt be able to update without a name"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
45
74
|
def test_delete
|
46
75
|
zoo_count_before = Zoo.all.length
|
47
76
|
new_zoo = Zoo.new({:name => "Foo"})
|
@@ -261,11 +290,16 @@ class FirstTest < Test::Unit::TestCase
|
|
261
290
|
new_zoo = Zoo.new({:name => "Foo"})
|
262
291
|
new_zoo.save
|
263
292
|
|
293
|
+
new_zoo2 = Zoo.new({:name => "Boo"})
|
294
|
+
new_zoo2.save
|
295
|
+
|
264
296
|
animal_kind = "mouse"
|
265
297
|
Animal.new(new_zoo, {:kind => animal_kind, :age => 42, :male => true}).save
|
266
298
|
Animal.new(new_zoo, {:kind => animal_kind, :age => 42, :male => false}).save
|
299
|
+
Animal.new(new_zoo2, {:kind => animal_kind, :age => 42, :male => false}).save
|
267
300
|
|
268
301
|
assert_equal 2, Zoo.all.first.animals.length
|
302
|
+
assert_equal 1, Zoo.all.last.animals.length
|
269
303
|
assert_equal 1, Zoo.all.first.animals.males_only.length
|
270
304
|
assert_equal true, Zoo.all.first.animals.males_only.first.male
|
271
305
|
|
@@ -297,5 +331,65 @@ class FirstTest < Test::Unit::TestCase
|
|
297
331
|
|
298
332
|
assert_equal ["Foo"], reloaded_parent.child_filters.child_nnn("Foo").map(&:bfield)
|
299
333
|
end
|
334
|
+
|
335
|
+
def test_no_param_filter
|
336
|
+
p1 = ParentFilter.new({:afield => "Foo"})
|
337
|
+
p2 = ParentFilter.new({:afield => "Bar"})
|
338
|
+
p1.save
|
339
|
+
p2.save
|
340
|
+
|
341
|
+
no_param = ParentFilter.no_param
|
342
|
+
assert_equal ["Foo"], no_param.map(&:afield)
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_has_many
|
346
|
+
Zoo.new(:name => "Foo1").save
|
347
|
+
Zoo.new(:name => "Foo2").save
|
348
|
+
assert_equal 2, Zoo.all.length
|
349
|
+
all_zoo_ids = Zoo.all.map(&:id)
|
350
|
+
v1 = ZooOwner.new({:name => "Foo", :zoo_ids => all_zoo_ids})
|
351
|
+
v1.save
|
352
|
+
|
353
|
+
v1_reloaded = ZooOwner.all.first
|
354
|
+
assert_equal all_zoo_ids, v1_reloaded.zoo_ids
|
355
|
+
|
356
|
+
url = v1.resource_location + '/' + Zoo.resource_name
|
357
|
+
Arrest::Source.source.cheat_collection(url, v1_reloaded.zoo_ids)
|
358
|
+
assert_equal 2,v1_reloaded.zoos.length
|
359
|
+
assert_equal "Foo1", v1_reloaded.zoos.first.name
|
360
|
+
end
|
361
|
+
|
362
|
+
def test_build
|
363
|
+
v1 = ZooOwner.new({:name => "Foo"})
|
364
|
+
v1.save
|
365
|
+
|
366
|
+
zoo = v1.zoos.build
|
367
|
+
assert_equal v1.id, zoo.zoo_owner_id
|
368
|
+
end
|
369
|
+
|
370
|
+
def test_scope_has_many
|
371
|
+
z1 = Zoo.new(:name => "Foo1", :open => true)
|
372
|
+
z1.save
|
373
|
+
z2 = Zoo.new(:name => "Foo2", :open => false)
|
374
|
+
z2.save
|
375
|
+
z3 = Zoo.new(:name => "Foo3", :open => true)
|
376
|
+
z3.save
|
377
|
+
assert_equal 3, Zoo.all.length
|
378
|
+
all_zoo_ids = [z1.id, z2.id]
|
379
|
+
v1 = ZooOwner.new({:name => "Foo", :zoo_ids => all_zoo_ids})
|
380
|
+
v1.save
|
381
|
+
|
382
|
+
v1_reloaded = ZooOwner.all.first
|
383
|
+
assert_equal all_zoo_ids, v1_reloaded.zoo_ids
|
384
|
+
|
385
|
+
url = v1.resource_location + '/' + Zoo.resource_name
|
386
|
+
Arrest::Source.source.cheat_collection(url, v1_reloaded.zoo_ids)
|
387
|
+
assert_equal 2,v1_reloaded.zoos.length
|
388
|
+
assert_equal "Foo1", v1_reloaded.zoos.first.name
|
389
|
+
|
390
|
+
assert_equal 1, v1_reloaded.zoos.open_filter.length
|
391
|
+
assert_equal "Foo1", v1_reloaded.zoos.open_filter.first.name
|
392
|
+
assert_equal 3, Zoo.all.length
|
393
|
+
end
|
300
394
|
end
|
301
395
|
|
data/test/validations.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'arrest'
|
3
|
+
|
4
|
+
class PresenceOfClass
|
5
|
+
include Arrest::Validatable
|
6
|
+
attr_accessor :foo
|
7
|
+
|
8
|
+
validates_presence_of :foo
|
9
|
+
|
10
|
+
def initialize foo
|
11
|
+
@foo = foo
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class PresenceOfTwo
|
16
|
+
include Arrest::Validatable
|
17
|
+
attr_accessor :foo, :bar
|
18
|
+
|
19
|
+
validates_presence_of :foo
|
20
|
+
validates_presence_of :bar
|
21
|
+
|
22
|
+
def initialize foo = nil, bar = nil
|
23
|
+
@foo = foo
|
24
|
+
@bar = bar
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class InheritedPresence < PresenceOfClass
|
29
|
+
attr_accessor :baz
|
30
|
+
|
31
|
+
validates_presence_of :baz
|
32
|
+
|
33
|
+
def initialize foo = nil, baz = nil
|
34
|
+
super foo
|
35
|
+
@baz = baz
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class CustomVal
|
40
|
+
include Arrest::Validatable
|
41
|
+
attr_accessor :foo
|
42
|
+
|
43
|
+
validates :is_foo
|
44
|
+
|
45
|
+
def initialize foo=nil
|
46
|
+
@foo = foo
|
47
|
+
end
|
48
|
+
|
49
|
+
def is_foo
|
50
|
+
if self.foo != "Foo"
|
51
|
+
[Arrest::Validations::ValidationError.new(:foo, "is no foo")]
|
52
|
+
else
|
53
|
+
[]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class ValidationsTest < Test::Unit::TestCase
|
59
|
+
|
60
|
+
|
61
|
+
def setup
|
62
|
+
Arrest::Source.source = nil
|
63
|
+
#Arrest::Source.debug = true
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_prsnc
|
67
|
+
o0 = PresenceOfClass.new nil
|
68
|
+
assert o0.valid? == false, "Foo is '#{o0.foo}' -> not present and thus not valid!"
|
69
|
+
|
70
|
+
o1 = PresenceOfClass.new "Foo"
|
71
|
+
assert o1.valid?, "Foo is present and valid!"
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_presence_of_two
|
75
|
+
o = PresenceOfTwo.new
|
76
|
+
assert o.valid? == false, "Both missing, must not be valid"
|
77
|
+
|
78
|
+
o = PresenceOfTwo.new "foo"
|
79
|
+
assert o.valid? == false, "bar missing, must not be valid"
|
80
|
+
|
81
|
+
o = PresenceOfTwo.new nil, "bar"
|
82
|
+
assert o.valid? == false, "foo missing, must not be valid"
|
83
|
+
|
84
|
+
o = PresenceOfTwo.new '', "bar"
|
85
|
+
assert o.valid? == false, "foo missing, must not be valid"
|
86
|
+
|
87
|
+
o = PresenceOfTwo.new "foo", "bar"
|
88
|
+
assert o.valid?, "complete -> should be valid"
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_inheritance
|
92
|
+
o = InheritedPresence.new
|
93
|
+
assert o.valid? == false, "Both missing, shouldnt be valid"
|
94
|
+
|
95
|
+
o = InheritedPresence.new "Foo"
|
96
|
+
assert o.valid? == false, "Baz missing, shouldnt be valid"
|
97
|
+
|
98
|
+
o = InheritedPresence.new "Foo", ''
|
99
|
+
assert o.valid? == false, "Baz missing, shouldnt be valid"
|
100
|
+
|
101
|
+
o = InheritedPresence.new "", "Baz"
|
102
|
+
assert o.valid? == false, "Foo missing, shouldnt be valid"
|
103
|
+
|
104
|
+
o = InheritedPresence.new nil, "Baz"
|
105
|
+
assert o.valid? == false, "Foo missing, shouldnt be valid"
|
106
|
+
|
107
|
+
o = InheritedPresence.new "Foo", "Baz"
|
108
|
+
assert o.valid? , "Nothing missing, should be valid"
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_method_valid
|
112
|
+
o = CustomVal.new
|
113
|
+
assert o.valid? == false, "no foo is not valid"
|
114
|
+
|
115
|
+
o = CustomVal.new("Bar")
|
116
|
+
assert o.valid? == false, "Bar is not Foo thus is not valid"
|
117
|
+
|
118
|
+
o = CustomVal.new("Foo")
|
119
|
+
assert_equal "Foo", o.foo
|
120
|
+
assert o.valid?, "Foo should be valid"
|
121
|
+
end
|
122
|
+
|
123
|
+
# ================ inclusion_of ======
|
124
|
+
|
125
|
+
class InclusionOfClass
|
126
|
+
include Arrest::Validatable
|
127
|
+
|
128
|
+
attr_accessor :foo
|
129
|
+
|
130
|
+
validates_inclusion_of :foo, :in => ["Foo", "Bar"]
|
131
|
+
|
132
|
+
def initialize foo
|
133
|
+
@foo = foo
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_inclusion_of
|
138
|
+
invalids = [nil, '', "Baz", "foo", 3, true]
|
139
|
+
|
140
|
+
valids = ["Foo", "Bar"]
|
141
|
+
|
142
|
+
invalids.each do |iv|
|
143
|
+
o = InclusionOfClass.new(iv)
|
144
|
+
assert o.valid? == false, "#{iv} is not valid"
|
145
|
+
assert o.validate.map(&:attribute).include?(:foo), ":foo should be in list of invalid attributes when created with #{iv}"
|
146
|
+
end
|
147
|
+
|
148
|
+
valids.each do |v|
|
149
|
+
o = InclusionOfClass.new(v)
|
150
|
+
assert o.valid?
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
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.
|
4
|
+
version: 0.0.11
|
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:
|
12
|
+
date: 2012-01-09 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
16
|
-
requirement: &
|
16
|
+
requirement: &24668020 !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: *
|
24
|
+
version_requirements: *24668020
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: faraday
|
27
|
-
requirement: &
|
27
|
+
requirement: &24666840 !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: *
|
35
|
+
version_requirements: *24666840
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: activemodel
|
38
|
-
requirement: &
|
38
|
+
requirement: &24666120 !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: *
|
46
|
+
version_requirements: *24666120
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: bundler
|
49
|
-
requirement: &
|
49
|
+
requirement: &24640360 !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: *
|
57
|
+
version_requirements: *24640360
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rake
|
60
|
-
requirement: &
|
60
|
+
requirement: &24639500 !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: *
|
68
|
+
version_requirements: *24639500
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rdoc
|
71
|
-
requirement: &
|
71
|
+
requirement: &24639020 !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: *
|
79
|
+
version_requirements: *24639020
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rspec
|
82
|
-
requirement: &
|
82
|
+
requirement: &24638440 !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: *
|
90
|
+
version_requirements: *24638440
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rr
|
93
|
-
requirement: &
|
93
|
+
requirement: &24637760 !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: *
|
101
|
+
version_requirements: *24637760
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: simplecov
|
104
|
-
requirement: &
|
104
|
+
requirement: &24637300 !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: *
|
112
|
+
version_requirements: *24637300
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: rack
|
115
|
-
requirement: &
|
115
|
+
requirement: &24636880 !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: *
|
123
|
+
version_requirements: *24636880
|
124
124
|
description: Consume a rest API in a AR like fashion
|
125
125
|
email:
|
126
126
|
- axel.tetzlaff@fortytools.com
|
@@ -141,6 +141,9 @@ files:
|
|
141
141
|
- lib/arrest/attributes/has_attributes.rb
|
142
142
|
- lib/arrest/exceptions.rb
|
143
143
|
- lib/arrest/helper/child_collection.rb
|
144
|
+
- lib/arrest/helper/filter.rb
|
145
|
+
- lib/arrest/helper/has_many_collection.rb
|
146
|
+
- lib/arrest/helper/logger.rb
|
144
147
|
- lib/arrest/http_source.rb
|
145
148
|
- lib/arrest/mem_source.rb
|
146
149
|
- lib/arrest/nested_resource.rb
|
@@ -148,6 +151,10 @@ files:
|
|
148
151
|
- lib/arrest/root_resource.rb
|
149
152
|
- lib/arrest/source.rb
|
150
153
|
- lib/arrest/string_utils.rb
|
154
|
+
- lib/arrest/validations/inclusion_of.rb
|
155
|
+
- lib/arrest/validations/presence_of.rb
|
156
|
+
- lib/arrest/validations/validatable.rb
|
157
|
+
- lib/arrest/validations/validator.rb
|
151
158
|
- lib/arrest/version.rb
|
152
159
|
- spec/arrest_spec.rb
|
153
160
|
- spec/spec_helper.rb
|
@@ -156,6 +163,7 @@ files:
|
|
156
163
|
- test/models.rb
|
157
164
|
- test/nested_resource.rb
|
158
165
|
- test/unit.rb
|
166
|
+
- test/validations.rb
|
159
167
|
homepage: ''
|
160
168
|
licenses: []
|
161
169
|
post_install_message:
|