morpheus 0.3.8 → 0.3.9
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/.travis.yml +6 -0
- data/Gemfile +5 -0
- data/README.md +1 -1
- data/Rakefile +0 -8
- data/lib/morpheus/associations/association.rb +1 -1
- data/lib/morpheus/relation.rb +1 -1
- data/lib/morpheus/request.rb +11 -11
- data/lib/morpheus/type_caster.rb +58 -61
- data/lib/morpheus/url_builder.rb +34 -37
- data/lib/morpheus/version.rb +1 -1
- data/lib/morpheus.rb +3 -0
- data/morpheus.gemspec +0 -2
- data/spec/morpheus/base_spec.rb +39 -3
- data/spec/morpheus/request_queue_spec.rb +54 -8
- data/spec/morpheus/request_spec.rb +1 -2
- data/spec/morpheus/response_spec.rb +25 -29
- data/spec/morpheus/type_caster_spec.rb +34 -47
- data/spec/morpheus/url_builder_spec.rb +97 -9
- data/spec/spec_helper.rb +7 -0
- metadata +5 -36
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Morpheus
|
1
|
+
# Morpheus [](http://travis-ci.org/#!/ryanmoran/morpheus)
|
2
2
|
## A RESTful API Client library built over Typhoeus
|
3
3
|
* The project is working toward a DSL that is very ActiveResource/ActiveRecord-like with some features stolen from other great libraries like DataMapper.
|
4
4
|
* We started working on this at a point when we felt we were pushing ActiveResource to its limits.
|
data/Rakefile
CHANGED
@@ -7,12 +7,4 @@ task :default => :spec
|
|
7
7
|
|
8
8
|
desc 'Run specs'
|
9
9
|
RSpec::Core::RakeTask.new do |t|
|
10
|
-
t.pattern = './spec/**/*_spec.rb'
|
11
|
-
end
|
12
|
-
|
13
|
-
desc 'Generate code coverage'
|
14
|
-
RSpec::Core::RakeTask.new(:coverage) do |t|
|
15
|
-
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
16
|
-
t.rcov = true
|
17
|
-
t.rcov_opts = ['--exclude', 'spec']
|
18
10
|
end
|
@@ -85,7 +85,7 @@ module Morpheus
|
|
85
85
|
# request will be made.
|
86
86
|
def loaded_target
|
87
87
|
@target ||= load_target!
|
88
|
-
if Array === @target && !@filters.empty?
|
88
|
+
if ::Array === @target && !@filters.empty?
|
89
89
|
@filters.uniq.inject(@target.dup) do |target, filter|
|
90
90
|
filter.call(target)
|
91
91
|
end
|
data/lib/morpheus/relation.rb
CHANGED
data/lib/morpheus/request.rb
CHANGED
@@ -2,7 +2,7 @@ module Morpheus
|
|
2
2
|
class Request < Typhoeus::Request
|
3
3
|
attr_reader :path, :params, :method
|
4
4
|
|
5
|
-
|
5
|
+
def initialize(path, options = {})
|
6
6
|
if options[:method] == :put
|
7
7
|
options[:method] = :post
|
8
8
|
options[:params].merge!(:_method => :put)
|
@@ -12,30 +12,30 @@ module Morpheus
|
|
12
12
|
options[:password] = Configuration.password if Configuration.password
|
13
13
|
|
14
14
|
super(Configuration.host + path, options)
|
15
|
-
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
[method, url, params].
|
19
|
-
|
17
|
+
def cache_key
|
18
|
+
Digest::SHA1.hexdigest([method, url, params].inspect)
|
19
|
+
end
|
20
20
|
|
21
|
-
|
21
|
+
def response=(response)
|
22
22
|
RequestCache.cache[cache_key] = response
|
23
23
|
response.tag_for_caching!
|
24
24
|
super
|
25
|
-
|
25
|
+
end
|
26
26
|
|
27
|
-
|
27
|
+
def response
|
28
28
|
RequestQueue.run! if RequestQueue.has_request?(self)
|
29
29
|
RequestCache.cache[cache_key]|| super
|
30
|
-
|
30
|
+
end
|
31
31
|
|
32
|
-
|
32
|
+
def self.enqueue(method, path, params)
|
33
33
|
options = { :method => method }
|
34
34
|
options.merge!(:params => params) unless params.blank?
|
35
35
|
new(path, options).tap do |request|
|
36
36
|
RequestQueue.enqueue(request)
|
37
37
|
end
|
38
|
-
|
38
|
+
end
|
39
39
|
|
40
40
|
end
|
41
41
|
end
|
data/lib/morpheus/type_caster.rb
CHANGED
@@ -1,79 +1,76 @@
|
|
1
1
|
module Morpheus
|
2
|
-
|
2
|
+
module TypeCaster
|
3
|
+
extend self
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
else
|
23
|
-
raise UnrecognizedTypeCastClass, "Can't typecast to #{typecast_class}!"
|
24
|
-
end
|
5
|
+
def cast(value, typecast_class)
|
6
|
+
case typecast_class
|
7
|
+
when NilClass
|
8
|
+
value
|
9
|
+
when :string
|
10
|
+
parse_string(value)
|
11
|
+
when :integer
|
12
|
+
parse_integer(value)
|
13
|
+
when :datetime
|
14
|
+
parse_datetime(value)
|
15
|
+
when :date
|
16
|
+
parse_date(value)
|
17
|
+
when :time
|
18
|
+
parse_time(value)
|
19
|
+
when :boolean
|
20
|
+
parse_boolean(value)
|
21
|
+
else
|
22
|
+
raise UnrecognizedTypeCastClass, "Can't typecast to #{typecast_class}!"
|
25
23
|
end
|
24
|
+
end
|
26
25
|
|
27
|
-
|
26
|
+
private
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
def parse_integer(value)
|
34
|
-
if value.respond_to?(:to_i)
|
35
|
-
value.to_i
|
36
|
-
else
|
37
|
-
case value
|
38
|
-
when TrueClass then 1
|
39
|
-
when FalseClass then 0
|
40
|
-
when Date then value.to_time.utc.to_i
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
28
|
+
def parse_string(value)
|
29
|
+
value.to_s
|
30
|
+
end
|
44
31
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
32
|
+
def parse_integer(value)
|
33
|
+
if value.respond_to?(:to_i)
|
34
|
+
value.to_i
|
35
|
+
else
|
36
|
+
case value
|
37
|
+
when TrueClass then 1
|
38
|
+
when FalseClass then 0
|
39
|
+
when Date then value.to_time.utc.to_i
|
50
40
|
end
|
51
|
-
rescue ArgumentError
|
52
|
-
nil
|
53
41
|
end
|
42
|
+
end
|
54
43
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
44
|
+
def parse_datetime(value)
|
45
|
+
if value.respond_to?(:to_datetime)
|
46
|
+
value.to_datetime
|
47
|
+
else
|
48
|
+
DateTime.parse(value) unless [TrueClass, FalseClass, NilClass, Fixnum].include?(value.class)
|
61
49
|
end
|
50
|
+
rescue ArgumentError
|
51
|
+
nil
|
52
|
+
end
|
62
53
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
rescue ArgumentError
|
70
|
-
nil
|
54
|
+
def parse_date(value)
|
55
|
+
if value.respond_to?(:to_time)
|
56
|
+
parse_time(value).try(:to_date)
|
57
|
+
else
|
58
|
+
Date.parse(value) unless [TrueClass, FalseClass, NilClass, Fixnum].include?(value.class)
|
71
59
|
end
|
60
|
+
end
|
72
61
|
|
73
|
-
|
74
|
-
|
62
|
+
def parse_time(value)
|
63
|
+
if value.respond_to?(:to_time)
|
64
|
+
value.to_time
|
65
|
+
else
|
66
|
+
Time.parse(value) unless [TrueClass, FalseClass, NilClass, Fixnum].include?(value.class)
|
75
67
|
end
|
68
|
+
rescue ArgumentError
|
69
|
+
nil
|
70
|
+
end
|
76
71
|
|
72
|
+
def parse_boolean(value)
|
73
|
+
!["nil", nil, "false", false, "0", 0].include?(value)
|
77
74
|
end
|
78
75
|
|
79
76
|
end
|
data/lib/morpheus/url_builder.rb
CHANGED
@@ -1,51 +1,48 @@
|
|
1
1
|
module Morpheus
|
2
|
-
|
2
|
+
module UrlBuilder
|
3
|
+
extend self
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
"/#{klass.plural_url_name}/#{id}"
|
8
|
-
end
|
9
|
-
|
10
|
-
def find_some(klass, ids)
|
11
|
-
["/#{klass.plural_url_name}", { :ids => ids }]
|
12
|
-
end
|
5
|
+
def find_one(klass, id)
|
6
|
+
"/#{klass.plural_url_name}/#{id}"
|
7
|
+
end
|
13
8
|
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
def find_some(klass, ids)
|
10
|
+
["/#{klass.plural_url_name}", { :ids => ids }]
|
11
|
+
end
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
[url_base, parameters]
|
22
|
-
end
|
13
|
+
def find_all(klass)
|
14
|
+
"/#{klass.plural_url_name}"
|
15
|
+
end
|
23
16
|
|
24
|
-
|
25
|
-
|
26
|
-
|
17
|
+
def save(klass, id, parameters)
|
18
|
+
url_base = "/#{klass.plural_url_name}"
|
19
|
+
url_base << "/#{id}" if id
|
20
|
+
[url_base, parameters]
|
21
|
+
end
|
27
22
|
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
def belongs_to(klass, id)
|
24
|
+
"/#{klass.plural_url_name}/#{id}"
|
25
|
+
end
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
def has_one(primary_class, primary_key, foreign_class)
|
28
|
+
"/#{primary_class.plural_url_name}/#{primary_key}/#{foreign_class.singular_url_name}"
|
29
|
+
end
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
url_base
|
40
|
-
else
|
41
|
-
[url_base, parameters]
|
42
|
-
end
|
43
|
-
end
|
31
|
+
def has_many(primary_class, primary_key, foreign_class)
|
32
|
+
"/#{primary_class.plural_url_name}/#{primary_key}/#{foreign_class.plural_url_name}"
|
33
|
+
end
|
44
34
|
|
45
|
-
|
46
|
-
|
35
|
+
def relation(klass, parameters = {})
|
36
|
+
url_base = "/#{klass.plural_url_name}"
|
37
|
+
if parameters.empty?
|
38
|
+
url_base
|
39
|
+
else
|
40
|
+
[url_base, parameters]
|
47
41
|
end
|
42
|
+
end
|
48
43
|
|
44
|
+
def destroy(klass, id)
|
45
|
+
"/#{klass.plural_url_name}/#{id}"
|
49
46
|
end
|
50
47
|
|
51
48
|
end
|
data/lib/morpheus/version.rb
CHANGED
data/lib/morpheus.rb
CHANGED
data/morpheus.gemspec
CHANGED
@@ -25,6 +25,4 @@ Gem::Specification.new do |gem|
|
|
25
25
|
gem.add_development_dependency 'rails', '>= 3.0.0'
|
26
26
|
gem.add_development_dependency 'sqlite3', '~> 1.3.3'
|
27
27
|
gem.add_development_dependency 'rspec-rails', '~> 2.8.1'
|
28
|
-
gem.add_development_dependency 'rcov', '~> 0.9.11'
|
29
|
-
gem.add_development_dependency 'autotest-standalone', '~> 4.5.9'
|
30
28
|
end
|
data/spec/morpheus/base_spec.rb
CHANGED
@@ -83,8 +83,7 @@ describe Morpheus::Base do
|
|
83
83
|
@auto.attributes.should eql(HashWithIndifferentAccess.new({ :id => nil, :bhp => nil, :wheels => nil, :hybrid => nil, :name => nil }))
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
87
|
-
context 'when an attributes hash is supplied' do
|
86
|
+
context 'when an attributes hash is supplied' do
|
88
87
|
before(:each) do
|
89
88
|
@auto = Automobile.new(
|
90
89
|
:bhp => 300,
|
@@ -115,7 +114,44 @@ describe Morpheus::Base do
|
|
115
114
|
end
|
116
115
|
|
117
116
|
describe Morpheus::Base, '#==' do
|
118
|
-
|
117
|
+
let(:attributes) { { :id => 1, :name => 'Fido' } }
|
118
|
+
|
119
|
+
context 'when comparing objects that are actually referencing the same memory' do
|
120
|
+
it 'returns true' do
|
121
|
+
dog_1 = Dog.new(attributes)
|
122
|
+
dog_2 = dog_1
|
123
|
+
dog_1.should ==(dog_2)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'when comparing objects that are of the same class' do
|
128
|
+
context 'that have the same id' do
|
129
|
+
context 'that are not new records' do
|
130
|
+
it 'returns true' do
|
131
|
+
dog_1 = Dog.new(attributes)
|
132
|
+
dog_2 = Dog.new(attributes)
|
133
|
+
dog_1.should ==(dog_2)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'that are new records' do
|
138
|
+
it 'returns false' do
|
139
|
+
dog_1 = Dog.new(attributes.except(:id))
|
140
|
+
dog_2 = Dog.new(attributes.except(:id))
|
141
|
+
dog_1.should_not ==(dog_2)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'that do not have the same id' do
|
147
|
+
it 'returns false' do
|
148
|
+
dog_1 = Dog.new(attributes)
|
149
|
+
dog_2 = Dog.new(attributes)
|
150
|
+
dog_2.id = 2
|
151
|
+
dog_1.should_not ==(dog_2)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
119
155
|
end
|
120
156
|
|
121
157
|
describe Morpheus::Base, '.base_class' do
|
@@ -1,37 +1,83 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Morpheus::RequestQueue do
|
4
|
+
let(:rq) { Morpheus::RequestQueue }
|
5
|
+
let(:app) { mock.tap { |a| a.stub(:call) } }
|
6
|
+
let(:request) { mock(:cache_key => 321) }
|
7
|
+
let(:env) { mock }
|
8
|
+
let(:cached_request) { mock(:cache_key => 123) }
|
9
|
+
let(:response) { mock }
|
10
|
+
let(:queue) { rq.new(app) }
|
4
11
|
|
5
12
|
describe '#initialize' do
|
6
|
-
|
13
|
+
it 'acts as Rack Middleware, taking an app initialization params' do
|
14
|
+
queue = rq.new(app)
|
15
|
+
queue.instance_variable_get('@app').should eql(app)
|
16
|
+
end
|
7
17
|
end
|
8
18
|
|
9
19
|
describe '#call' do
|
10
|
-
|
20
|
+
it 'clears the queue' do
|
21
|
+
rq.enqueue(request)
|
22
|
+
rq.queue.length.should eql(1)
|
23
|
+
queue.call(env)
|
24
|
+
rq.queue.length.should eql(0)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'calls #call on the @app instance variable' do
|
28
|
+
app.should_receive(:call).with(env)
|
29
|
+
queue.call(env)
|
30
|
+
end
|
11
31
|
end
|
12
32
|
|
13
33
|
describe '.enqueue' do
|
14
|
-
|
34
|
+
it 'puts the passed parameter onto the queue' do
|
35
|
+
rq.enqueue(request)
|
36
|
+
rq.queue.should include(request)
|
37
|
+
end
|
15
38
|
end
|
16
39
|
|
17
40
|
describe '.queue' do
|
18
|
-
|
41
|
+
it 'defaults to an empty array' do
|
42
|
+
rq.queue.length.should eql(0)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns the array stored in the @queue instance variable' do
|
46
|
+
rq.enqueue(request)
|
47
|
+
rq.queue.should include(request)
|
48
|
+
end
|
19
49
|
end
|
20
50
|
|
21
51
|
describe '.uncached_queue' do
|
22
|
-
|
52
|
+
it 'returns an array of requests that have been queued, but are not in the cache' do
|
53
|
+
Morpheus::RequestCache.cache[cached_request.cache_key] = response
|
54
|
+
rq.enqueue(request)
|
55
|
+
rq.enqueue(cached_request)
|
56
|
+
rq.uncached_queue.should include(request)
|
57
|
+
rq.uncached_queue.should_not include(cached_request)
|
58
|
+
end
|
23
59
|
end
|
24
60
|
|
25
61
|
describe '.hydra' do
|
26
|
-
|
62
|
+
it 'returns the hydra contained in the Configuration' do
|
63
|
+
rq.hydra.should eql(Morpheus::Configuration.hydra)
|
64
|
+
end
|
27
65
|
end
|
28
66
|
|
29
67
|
describe '.run!' do
|
30
|
-
|
68
|
+
it 'queues each uncached request into the hydra' do
|
69
|
+
rq.enqueue(request)
|
70
|
+
rq.hydra.should_receive(:queue).with(request)
|
71
|
+
rq.run!
|
72
|
+
end
|
31
73
|
end
|
32
74
|
|
33
75
|
describe '.has_request?' do
|
34
|
-
|
76
|
+
it 'returns true if the request is in the queue' do
|
77
|
+
rq.enqueue(request)
|
78
|
+
rq.should have_request(request)
|
79
|
+
rq.should_not have_request(cached_request)
|
80
|
+
end
|
35
81
|
end
|
36
82
|
|
37
83
|
end
|
@@ -12,8 +12,7 @@ describe Morpheus::Request do
|
|
12
12
|
|
13
13
|
describe '#cache_key' do
|
14
14
|
it 'returns a hash of the array [method, url, params]' do
|
15
|
-
|
16
|
-
request.cache_key.should eql(key)
|
15
|
+
request.cache_key.should eql('ad2b05e950b4cf408f6980799d67b7c968044068')
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
@@ -1,75 +1,71 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Morpheus::Response do
|
4
|
-
|
5
|
-
describe '#initialize' do
|
6
|
-
pending
|
7
|
-
end
|
4
|
+
let(:response) { Morpheus::Response.new(:code => 200, :headers => '', :body => '', :time => 0.3) }
|
8
5
|
|
9
6
|
describe '#cached?' do
|
10
7
|
context 'when the response is marked as cached' do
|
11
|
-
|
12
|
-
@response = Morpheus::Response.new({ :code => 200, :headers => '', :body => '', :time => 0.3 }, true)
|
13
|
-
end
|
8
|
+
let(:response) { Morpheus::Response.new({ :code => 200, :headers => '', :body => '', :time => 0.3 }, true) }
|
14
9
|
|
15
10
|
it 'returns true' do
|
16
|
-
|
11
|
+
response.should be_cached
|
17
12
|
end
|
18
13
|
end
|
19
14
|
|
20
15
|
context 'when the response is marked as not cached' do
|
21
|
-
|
22
|
-
@response = Morpheus::Response.new({ :code => 200, :headers => '', :body => '', :time => 0.3 }, false)
|
23
|
-
end
|
16
|
+
let(:response) { Morpheus::Response.new({ :code => 200, :headers => '', :body => '', :time => 0.3 }, false) }
|
24
17
|
|
25
18
|
it 'returns false' do
|
26
|
-
|
19
|
+
response.should_not be_cached
|
27
20
|
end
|
28
21
|
end
|
29
22
|
|
30
23
|
context 'when the response is not marked as cached or otherwise' do
|
31
|
-
before(:each) do
|
32
|
-
@response = Morpheus::Response.new(:code => 200, :headers => '', :body => '', :time => 0.3)
|
33
|
-
end
|
34
|
-
|
35
24
|
it 'returns false' do
|
36
|
-
|
25
|
+
response.should_not be_cached
|
37
26
|
end
|
38
27
|
end
|
39
28
|
end
|
40
29
|
|
41
30
|
describe '#tag_for_caching!' do
|
42
|
-
|
31
|
+
it 'sets the @tagged_for_caching instance variable to true' do
|
32
|
+
response.should_not be_tagged_for_caching
|
33
|
+
response.tag_for_caching!
|
34
|
+
response.should be_tagged_for_caching
|
35
|
+
end
|
43
36
|
end
|
44
37
|
|
45
38
|
describe '#tagged_for_caching?' do
|
46
|
-
|
39
|
+
it 'returns false as a default value' do
|
40
|
+
response.should_not be_tagged_for_caching
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns true when a response has been tagged for caching' do
|
44
|
+
response.tag_for_caching!
|
45
|
+
response.should be_tagged_for_caching
|
46
|
+
end
|
47
47
|
end
|
48
48
|
|
49
49
|
describe '#respond_to?' do
|
50
|
-
|
51
|
-
@typhoeus_response = Typhoeus::Response.new(:code => 200, :headers => '', :body => '', :time => 0.3)
|
52
|
-
@response = Morpheus::Response.new(:code => 200, :headers => '', :body => '', :time => 0.3)
|
53
|
-
end
|
50
|
+
let(:typhoeus_response) { Typhoeus::Response.new(:code => 200, :headers => '', :body => '', :time => 0.3) }
|
54
51
|
|
55
52
|
it 'responds to all methods defined on itself' do
|
56
|
-
|
57
|
-
|
53
|
+
response.methods.reject { |method| method == :respond_to? }.each do |method|
|
54
|
+
response.should respond_to(method)
|
58
55
|
end
|
59
56
|
end
|
60
57
|
|
61
58
|
it 'responds to all methods defined on the Typhoeus::Response object it wraps' do
|
62
|
-
|
63
|
-
|
59
|
+
typhoeus_response.methods.each do |method|
|
60
|
+
response.should respond_to(method)
|
64
61
|
end
|
65
62
|
end
|
66
63
|
end
|
67
64
|
|
68
65
|
describe '#method_missing' do
|
69
66
|
it 'wraps a Typhoeus::Response object' do
|
70
|
-
@response = Morpheus::Response.new
|
71
67
|
Typhoeus::Response.new.methods.each do |method|
|
72
|
-
|
68
|
+
response.should respond_to(method.to_sym)
|
73
69
|
end
|
74
70
|
end
|
75
71
|
end
|
@@ -3,70 +3,54 @@ require 'spec_helper'
|
|
3
3
|
describe Morpheus::TypeCaster do
|
4
4
|
|
5
5
|
describe '.cast' do
|
6
|
-
|
7
|
-
it 'casts "hello" to "hello"' do
|
8
|
-
Morpheus::TypeCaster.cast('hello', nil).should eql('hello')
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'casts "2011-04-10" to "2011-04-10"' do
|
12
|
-
Morpheus::TypeCaster.cast('2011-04-10', nil).should eql('2011-04-10')
|
13
|
-
end
|
6
|
+
let(:object) { Object.new }
|
14
7
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
it 'casts "10-04-2011T05:00:00Z" to "10-04-2011T05:00:00Z"' do
|
20
|
-
Morpheus::TypeCaster.cast('10-04-2011T05:00:00Z', nil).should eql('10-04-2011T05:00:00Z')
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'casts "true" to "true"' do
|
24
|
-
Morpheus::TypeCaster.cast('true', nil).should eql('true')
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'casts 4 to 4' do
|
28
|
-
Morpheus::TypeCaster.cast(4, nil).should eql(4)
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'casts true to true' do
|
32
|
-
Morpheus::TypeCaster.cast(true, nil).should eql(true)
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'cast DateTime to DateTime' do
|
36
|
-
Morpheus::TypeCaster.cast(DateTime.parse('10-04-2011T05:00:00Z'), nil).should eql(DateTime.parse('10-04-2011T05:00:00Z'))
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'casts Date to Date' do
|
40
|
-
Morpheus::TypeCaster.cast(Date.parse('2011-04-10'), nil).should eql(Date.parse('2011-04-10'))
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'casts Time to Time' do
|
44
|
-
Morpheus::TypeCaster.cast(Time.parse('10-04-2011T05:00:00Z'), nil).should eql(Time.parse('10-04-2011T05:00:00Z'))
|
8
|
+
context 'when the typecast_class is nil' do
|
9
|
+
it 'returns the given value unchanged' do
|
10
|
+
Morpheus::TypeCaster.cast(object, nil).should eql(object)
|
45
11
|
end
|
46
12
|
end
|
47
13
|
|
48
14
|
context 'when the typecast_class is String' do
|
49
|
-
|
15
|
+
it 'delegates to parse_string with the given value' do
|
16
|
+
Morpheus::TypeCaster.should_receive(:parse_string).with(object)
|
17
|
+
Morpheus::TypeCaster.cast(object, :string)
|
18
|
+
end
|
50
19
|
end
|
51
20
|
|
52
21
|
context 'when the typecast_class is Integer' do
|
53
|
-
|
22
|
+
it 'delegates to parse_integer with the given value' do
|
23
|
+
Morpheus::TypeCaster.should_receive(:parse_integer).with(object)
|
24
|
+
Morpheus::TypeCaster.cast(object, :integer)
|
25
|
+
end
|
54
26
|
end
|
55
27
|
|
56
28
|
context 'when the typecast_class is DateTime' do
|
57
|
-
|
29
|
+
it 'delegates to parse_datetime with the given value' do
|
30
|
+
Morpheus::TypeCaster.should_receive(:parse_datetime).with(object)
|
31
|
+
Morpheus::TypeCaster.cast(object, :datetime)
|
32
|
+
end
|
58
33
|
end
|
59
34
|
|
60
35
|
context 'when the typecast_class is Date' do
|
61
|
-
|
36
|
+
it 'delegates to parse_date with the given value' do
|
37
|
+
Morpheus::TypeCaster.should_receive(:parse_date).with(object)
|
38
|
+
Morpheus::TypeCaster.cast(object, :date)
|
39
|
+
end
|
62
40
|
end
|
63
41
|
|
64
42
|
context 'when the typecast_class is Time' do
|
65
|
-
|
43
|
+
it 'delegates to parse_time with the given value' do
|
44
|
+
Morpheus::TypeCaster.should_receive(:parse_time).with(object)
|
45
|
+
Morpheus::TypeCaster.cast(object, :time)
|
46
|
+
end
|
66
47
|
end
|
67
48
|
|
68
49
|
context 'when the typecast_class is Boolean' do
|
69
|
-
|
50
|
+
it 'delegates to parse_boolean with the given value' do
|
51
|
+
Morpheus::TypeCaster.should_receive(:parse_boolean).with(object)
|
52
|
+
Morpheus::TypeCaster.cast(object, :boolean)
|
53
|
+
end
|
70
54
|
end
|
71
55
|
|
72
56
|
context 'when the typecast_class is unknown' do
|
@@ -116,7 +100,8 @@ describe Morpheus::TypeCaster do
|
|
116
100
|
end
|
117
101
|
|
118
102
|
it 'casts Time to "10-04-2011T05:00:00Z"' do
|
119
|
-
|
103
|
+
time = Time.parse('10-04-2011T05:00:00Z')
|
104
|
+
Morpheus::TypeCaster.cast(time, :string).should eql(time.to_s)
|
120
105
|
end
|
121
106
|
end
|
122
107
|
|
@@ -158,7 +143,8 @@ describe Morpheus::TypeCaster do
|
|
158
143
|
end
|
159
144
|
|
160
145
|
it 'casts Date to 1302393600' do
|
161
|
-
|
146
|
+
date = Date.parse('2011-04-10')
|
147
|
+
Morpheus::TypeCaster.cast(date, :integer).should eql(date.to_time.utc.to_i)
|
162
148
|
end
|
163
149
|
|
164
150
|
it 'casts Time to 1302411600' do
|
@@ -246,7 +232,8 @@ describe Morpheus::TypeCaster do
|
|
246
232
|
end
|
247
233
|
|
248
234
|
it 'casts Time to Date' do
|
249
|
-
|
235
|
+
time = Time.parse('10-04-2011T05:00:00Z')
|
236
|
+
Morpheus::TypeCaster.cast(time, :date).should eql(time.to_time.to_date)
|
250
237
|
end
|
251
238
|
end
|
252
239
|
|
@@ -3,39 +3,127 @@ require 'spec_helper'
|
|
3
3
|
describe Morpheus::UrlBuilder do
|
4
4
|
|
5
5
|
describe '.find_one' do
|
6
|
-
|
6
|
+
let(:find_one) { Morpheus::UrlBuilder.find_one(Dog, 1) }
|
7
|
+
|
8
|
+
it 'returns a string matching "/plural_class_name/id"' do
|
9
|
+
find_one.should eql('/dogs/1')
|
10
|
+
end
|
7
11
|
end
|
8
12
|
|
9
13
|
describe '.find_some' do
|
10
|
-
|
14
|
+
let(:find_some) { Morpheus::UrlBuilder.find_some(Dog, [1,2,3]) }
|
15
|
+
|
16
|
+
it 'returns an array' do
|
17
|
+
find_some.should be_kind_of(Array)
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'within the returned array' do
|
21
|
+
it 'contains a string matching "/plural_class_name"' do
|
22
|
+
find_some.should include('/dogs')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'contains an array containing a hash with key :ids' do
|
26
|
+
find_some.should include({ :ids => [1,2,3] })
|
27
|
+
end
|
28
|
+
end
|
11
29
|
end
|
12
30
|
|
13
31
|
describe '.find_all' do
|
14
|
-
|
32
|
+
let(:find_all) { Morpheus::UrlBuilder.find_all(Dog) }
|
33
|
+
|
34
|
+
it 'returns a string matching "/plural_class_name"' do
|
35
|
+
find_all.should eql('/dogs')
|
36
|
+
end
|
15
37
|
end
|
16
38
|
|
17
39
|
describe '.save' do
|
18
|
-
|
40
|
+
let(:parameters) { { :name => 'Fido' } }
|
41
|
+
let(:save) { Morpheus::UrlBuilder.save(Dog, 1, parameters) }
|
42
|
+
|
43
|
+
it 'returns an array' do
|
44
|
+
save.should be_kind_of(Array)
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'within the returned array' do
|
48
|
+
context 'when there is an id' do
|
49
|
+
it 'contains a string matching "/plural_class_name/id"' do
|
50
|
+
save.should include('/dogs/1')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when there is no id' do
|
55
|
+
let(:save) { Morpheus::UrlBuilder.save(Dog, nil, parameters) }
|
56
|
+
|
57
|
+
it 'contains a string matching "/plural_class_name"' do
|
58
|
+
save.should include('/dogs')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'contains the parameters passed in as arguments' do
|
63
|
+
save.should include(parameters)
|
64
|
+
end
|
65
|
+
end
|
19
66
|
end
|
20
67
|
|
21
68
|
describe '.belongs_to' do
|
22
|
-
|
69
|
+
let(:belongs_to) { Morpheus::UrlBuilder.belongs_to(Dog, 1) }
|
70
|
+
|
71
|
+
it 'returns a string matching "/plural_class_name/id"' do
|
72
|
+
belongs_to.should eql('/dogs/1')
|
73
|
+
end
|
23
74
|
end
|
24
75
|
|
25
76
|
describe '.has_one' do
|
26
|
-
|
77
|
+
let(:has_one) { Morpheus::UrlBuilder.has_one(Meeting, 1, Speaker) }
|
78
|
+
|
79
|
+
it 'returns a string matching "/plural_class_name/id/singular_foreign_class_name"' do
|
80
|
+
has_one.should eql('/meetings/1/speaker')
|
81
|
+
end
|
27
82
|
end
|
28
83
|
|
29
84
|
describe '.has_many' do
|
30
|
-
|
85
|
+
let(:has_many) { Morpheus::UrlBuilder.has_many(Meeting, 1, Attendee) }
|
86
|
+
|
87
|
+
it 'returns a string matching "/plural_class_name/id/plural_foreign_class_name"' do
|
88
|
+
has_many.should eql('/meetings/1/attendees')
|
89
|
+
end
|
31
90
|
end
|
32
91
|
|
33
92
|
describe '.relation' do
|
34
|
-
|
93
|
+
context 'when there are parameters' do
|
94
|
+
let(:relation) { Morpheus::UrlBuilder.relation(Dog) }
|
95
|
+
|
96
|
+
it 'returns a string matching "/plural_class_name"' do
|
97
|
+
relation.should eql('/dogs')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when there are no parameters' do
|
102
|
+
let(:parameters) { { :name => 'Fido' } }
|
103
|
+
let(:relation) { Morpheus::UrlBuilder.relation(Dog, parameters) }
|
104
|
+
|
105
|
+
it 'returns an Array' do
|
106
|
+
relation.should be_kind_of(Array)
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'within the returned array' do
|
110
|
+
it 'contains a string matching "/plural_class_name"' do
|
111
|
+
relation.should include('/dogs')
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'contains the parameters that were passed in as arguments' do
|
115
|
+
relation.should include(parameters)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
35
119
|
end
|
36
120
|
|
37
121
|
describe '.destroy' do
|
38
|
-
|
122
|
+
let(:destroy) { Morpheus::UrlBuilder.destroy(Dog, 1) }
|
123
|
+
|
124
|
+
it 'returns a string matching "/plural_class_name/id"' do
|
125
|
+
destroy.should eql('/dogs/1')
|
126
|
+
end
|
39
127
|
end
|
40
128
|
|
41
129
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
2
|
ENV['RAILS_ENV'] = 'test'
|
3
3
|
|
4
|
+
if ENV['COVERAGE']
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.start do
|
7
|
+
add_filter '/spec/'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
4
11
|
require File.expand_path('../dummy/config/environment.rb', __FILE__)
|
5
12
|
require 'rails/test_help'
|
6
13
|
require 'rspec/rails'
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpheus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 1
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 9
|
10
|
+
version: 0.3.9
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ryan Moran
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-02-
|
18
|
+
date: 2012-02-22 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -146,38 +146,6 @@ dependencies:
|
|
146
146
|
version: 2.8.1
|
147
147
|
type: :development
|
148
148
|
version_requirements: *id008
|
149
|
-
- !ruby/object:Gem::Dependency
|
150
|
-
name: rcov
|
151
|
-
prerelease: false
|
152
|
-
requirement: &id009 !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
|
-
requirements:
|
155
|
-
- - ~>
|
156
|
-
- !ruby/object:Gem::Version
|
157
|
-
hash: 45
|
158
|
-
segments:
|
159
|
-
- 0
|
160
|
-
- 9
|
161
|
-
- 11
|
162
|
-
version: 0.9.11
|
163
|
-
type: :development
|
164
|
-
version_requirements: *id009
|
165
|
-
- !ruby/object:Gem::Dependency
|
166
|
-
name: autotest-standalone
|
167
|
-
prerelease: false
|
168
|
-
requirement: &id010 !ruby/object:Gem::Requirement
|
169
|
-
none: false
|
170
|
-
requirements:
|
171
|
-
- - ~>
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
hash: 57
|
174
|
-
segments:
|
175
|
-
- 4
|
176
|
-
- 5
|
177
|
-
- 9
|
178
|
-
version: 4.5.9
|
179
|
-
type: :development
|
180
|
-
version_requirements: *id010
|
181
149
|
description: RESTful API Client
|
182
150
|
email:
|
183
151
|
- ryan.moran@revolutionprep.com
|
@@ -191,6 +159,7 @@ files:
|
|
191
159
|
- .autotest
|
192
160
|
- .gitignore
|
193
161
|
- .rspec
|
162
|
+
- .travis.yml
|
194
163
|
- Gemfile
|
195
164
|
- LICENSE.txt
|
196
165
|
- README.md
|