ddy_remote_resource 0.4.11 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Guardfile +3 -0
- data/lib/remote_resource.rb +77 -34
- data/lib/remote_resource/base.rb +20 -8
- data/lib/remote_resource/connection.rb +26 -5
- data/lib/remote_resource/connection_options.rb +5 -3
- data/lib/remote_resource/querying/finder_methods.rb +3 -3
- data/lib/remote_resource/querying/persistence_methods.rb +17 -12
- data/lib/remote_resource/request.rb +96 -62
- data/lib/remote_resource/response.rb +5 -1
- data/lib/remote_resource/rest.rb +13 -17
- data/lib/remote_resource/url_naming.rb +4 -10
- data/lib/remote_resource/url_naming_determination.rb +1 -3
- data/lib/remote_resource/util.rb +64 -0
- data/lib/remote_resource/version.rb +1 -1
- data/remote_resource.gemspec +2 -2
- data/spec/fixtures/text_file.txt +1 -0
- data/spec/integration/all_spec.rb +166 -0
- data/spec/integration/collection_prefix_spec.rb +99 -0
- data/spec/integration/create_spec.rb +181 -0
- data/spec/integration/destroy_spec.rb +252 -0
- data/spec/integration/find_by_spec.rb +168 -0
- data/spec/integration/find_spec.rb +139 -0
- data/spec/integration/headers_spec.rb +222 -0
- data/spec/integration/naming_spec.rb +138 -0
- data/spec/integration/save_spec.rb +320 -0
- data/spec/integration/update_attributes_spec.rb +221 -0
- data/spec/integration/where_spec.rb +152 -0
- data/spec/lib/extensions/ethon/easy/queryable_spec.rb +4 -4
- data/spec/lib/remote_resource/base_spec.rb +54 -110
- data/spec/lib/remote_resource/builder_spec.rb +1 -1
- data/spec/lib/remote_resource/collection_spec.rb +1 -1
- data/spec/lib/remote_resource/connection_options_spec.rb +20 -17
- data/spec/lib/remote_resource/connection_spec.rb +36 -27
- data/spec/lib/remote_resource/querying/finder_methods_spec.rb +199 -72
- data/spec/lib/remote_resource/querying/persistence_methods_spec.rb +228 -220
- data/spec/lib/remote_resource/request_spec.rb +313 -342
- data/spec/lib/remote_resource/response_spec.rb +9 -3
- data/spec/lib/remote_resource/rest_spec.rb +11 -11
- data/spec/lib/remote_resource/url_naming_determination_spec.rb +1 -1
- data/spec/lib/remote_resource/url_naming_spec.rb +7 -22
- data/spec/lib/remote_resource/util_spec.rb +56 -0
- data/spec/lib/remote_resource/version_spec.rb +2 -3
- data/spec/spec_helper.rb +37 -0
- metadata +33 -22
- data/lib/remote_resource/http_errors.rb +0 -33
- data/lib/remote_resource/response_handeling.rb +0 -48
@@ -26,6 +26,10 @@ module RemoteResource
|
|
26
26
|
original_response.response_code
|
27
27
|
end
|
28
28
|
|
29
|
+
def response_headers
|
30
|
+
original_response.headers
|
31
|
+
end
|
32
|
+
|
29
33
|
def sanitized_response_body
|
30
34
|
return empty_hash if response_body.blank?
|
31
35
|
return empty_hash if parsed_response_body.blank?
|
@@ -75,4 +79,4 @@ module RemoteResource
|
|
75
79
|
end
|
76
80
|
|
77
81
|
end
|
78
|
-
end
|
82
|
+
end
|
data/lib/remote_resource/rest.rb
CHANGED
@@ -1,28 +1,24 @@
|
|
1
1
|
module RemoteResource
|
2
2
|
module REST
|
3
|
-
extend ActiveSupport::Concern
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
def get(attributes = {}, connection_options = {})
|
5
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
connection_options = args[1] || {}
|
8
|
+
def put(attributes = {}, connection_options = {})
|
9
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
10
|
+
end
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
end
|
12
|
+
def patch(attributes = {}, connection_options = {})
|
13
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
17
14
|
end
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
connection_options = args[1] || {}
|
16
|
+
def post(attributes = {}, connection_options = {})
|
17
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
18
|
+
end
|
23
19
|
|
24
|
-
|
25
|
-
|
20
|
+
def delete(attributes = {}, connection_options = {})
|
21
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
26
22
|
end
|
27
23
|
|
28
24
|
end
|
@@ -10,25 +10,19 @@ module RemoteResource
|
|
10
10
|
|
11
11
|
module ClassMethods
|
12
12
|
|
13
|
-
def app_host(
|
14
|
-
|
13
|
+
def app_host(*_)
|
14
|
+
warn '[DEPRECATION] `.app_host` is deprecated. Please use a different method to determine the site.'
|
15
15
|
end
|
16
16
|
|
17
17
|
def base_url
|
18
|
-
|
18
|
+
warn '[DEPRECATION] `.base_url` is deprecated. Please use the connection_options[:base_url] when querying instead.'
|
19
19
|
end
|
20
20
|
|
21
21
|
def use_relative_model_naming?
|
22
22
|
true
|
23
23
|
end
|
24
24
|
|
25
|
-
private
|
26
|
-
|
27
|
-
def determined_url_naming
|
28
|
-
RemoteResource::UrlNamingDetermination.new self
|
29
|
-
end
|
30
|
-
|
31
25
|
end
|
32
26
|
|
33
27
|
end
|
34
|
-
end
|
28
|
+
end
|
@@ -14,9 +14,7 @@ module RemoteResource
|
|
14
14
|
path_prefix = connection_options.fetch(:path_prefix, resource_klass.path_prefix)
|
15
15
|
path_postfix = connection_options.fetch(:path_postfix, resource_klass.path_postfix)
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
"#{site}#{version.presence}#{path_prefix.presence}#{collection_prefix(check_collection_options)}/#{url_safe_relative_name}#{id}#{path_postfix.presence}"
|
17
|
+
File.join(site.to_s, version.to_s, path_prefix.to_s, collection_prefix(check_collection_options).to_s, url_safe_relative_name, id.to_s, path_postfix.to_s).chomp('/')
|
20
18
|
end
|
21
19
|
|
22
20
|
def collection_prefix(check_collection_options)
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module RemoteResource
|
2
|
+
module Util
|
3
|
+
|
4
|
+
FILTERED = '[FILTERED]'.freeze
|
5
|
+
|
6
|
+
def self.filter_params(query_string_or_json_body, filtered_params:)
|
7
|
+
filtered = query_string_or_json_body
|
8
|
+
filtered_params.each do |filtered_param|
|
9
|
+
filtered = filtered.to_s.gsub(/(?<="#{filtered_param}":|#{filtered_param}=)(.*?)(?=,|}|&|$)/, FILTERED)
|
10
|
+
end
|
11
|
+
filtered
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.encode_params_to_query(params)
|
15
|
+
if params.is_a?(String)
|
16
|
+
pairs = [params]
|
17
|
+
else
|
18
|
+
pairs = recursively_generate_query(params, nil)
|
19
|
+
end
|
20
|
+
|
21
|
+
URI.encode_www_form(pairs)
|
22
|
+
end
|
23
|
+
|
24
|
+
# This method is based on the monkey patched method:
|
25
|
+
# Ethon::Easy::Queryable#recursively_generate_pairs
|
26
|
+
#
|
27
|
+
# The monkey patch was needed to pass Array
|
28
|
+
# params without an index.
|
29
|
+
#
|
30
|
+
# The problem is described in typhoeus/typhoeus issue #320:
|
31
|
+
# https://github.com/typhoeus/typhoeus/issues/320
|
32
|
+
#
|
33
|
+
# The fix is described in dylanfareed/ethon commit 548033a:
|
34
|
+
# https://github.com/dylanfareed/ethon/commit/548033a8557a48203b7d49f3f98812bd79bc05e4
|
35
|
+
#
|
36
|
+
def self.recursively_generate_query(component, prefix, pairs = [])
|
37
|
+
case component
|
38
|
+
when Hash
|
39
|
+
component.each do |key, value|
|
40
|
+
key = prefix.nil? ? key : "#{prefix}[#{key}]"
|
41
|
+
|
42
|
+
if value.respond_to?(:each)
|
43
|
+
recursively_generate_query(value, key, pairs)
|
44
|
+
else
|
45
|
+
pairs.push([key, value.to_s])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
when Array
|
49
|
+
component.each do |value|
|
50
|
+
key = "#{prefix}[]"
|
51
|
+
|
52
|
+
if value.respond_to?(:each)
|
53
|
+
recursively_generate_query(value, key, pairs)
|
54
|
+
else
|
55
|
+
pairs.push([key, value.to_s])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
pairs
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/remote_resource.gemspec
CHANGED
@@ -22,10 +22,10 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency 'rake', '~> 10.4'
|
23
23
|
spec.add_development_dependency 'rspec', '~> 3.1'
|
24
24
|
spec.add_development_dependency 'pry', '~> 0.10'
|
25
|
-
spec.add_development_dependency 'webmock', '~> 1.24'
|
25
|
+
# spec.add_development_dependency 'webmock', '~> 1.24'
|
26
26
|
spec.add_development_dependency 'guard', '~> 2.14'
|
27
27
|
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
28
|
-
spec.add_development_dependency 'terminal-notifier-guard', '~> 1.6
|
28
|
+
spec.add_development_dependency 'terminal-notifier-guard', '~> 1.6'
|
29
29
|
|
30
30
|
spec.add_runtime_dependency 'activesupport', '~> 4.1'
|
31
31
|
spec.add_runtime_dependency 'activemodel', '~> 4.1'
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello world!
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe '.all' do
|
4
|
+
|
5
|
+
class Post
|
6
|
+
include RemoteResource::Base
|
7
|
+
|
8
|
+
self.site = 'https://www.example.com'
|
9
|
+
self.collection = true
|
10
|
+
self.root_element = :data
|
11
|
+
|
12
|
+
attribute :title, String
|
13
|
+
attribute :body, String
|
14
|
+
attribute :created_at, Time
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:response_body) do
|
18
|
+
{
|
19
|
+
data: [
|
20
|
+
{
|
21
|
+
id: 12,
|
22
|
+
title: 'Lorem Ipsum',
|
23
|
+
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
24
|
+
created_at: Time.new(2015, 10, 4, 9, 30, 0),
|
25
|
+
},
|
26
|
+
{
|
27
|
+
id: 14,
|
28
|
+
title: 'Mauris Purus',
|
29
|
+
body: 'Mauris purus urna, ultrices et suscipit ut, faucibus eget mauris.',
|
30
|
+
created_at: Time.new(2015, 12, 11, 11, 32, 0),
|
31
|
+
},
|
32
|
+
{
|
33
|
+
id: 16,
|
34
|
+
title: 'Vestibulum Commodo',
|
35
|
+
body: 'Vestibulum commodo fringilla suscipit.',
|
36
|
+
created_at: Time.new(2016, 2, 6, 18, 45, 0),
|
37
|
+
},
|
38
|
+
]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:expected_default_headers) do
|
43
|
+
{ 'Accept' => 'application/json', 'User-Agent' => "RemoteResource #{RemoteResource::VERSION}" }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'default behaviour' do
|
47
|
+
let!(:expected_request) do
|
48
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
49
|
+
mock_request.with(query: nil, body: nil, headers: expected_default_headers)
|
50
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
51
|
+
mock_request
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'performs the correct HTTP GET request' do
|
55
|
+
Post.all
|
56
|
+
expect(expected_request).to have_been_requested
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'builds the correct collection of resources' do
|
60
|
+
posts = Post.all
|
61
|
+
|
62
|
+
aggregate_failures do
|
63
|
+
expect(posts).to respond_to :each
|
64
|
+
expect(posts).to all(be_a(Post))
|
65
|
+
expect(posts.size).to eql 3
|
66
|
+
|
67
|
+
expect(posts[0].id).to eql 12
|
68
|
+
expect(posts[0].title).to eql 'Lorem Ipsum'
|
69
|
+
expect(posts[0].body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
70
|
+
expect(posts[0].created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
|
71
|
+
expect(posts[1].id).to eql 14
|
72
|
+
expect(posts[1].title).to eql 'Mauris Purus'
|
73
|
+
expect(posts[1].body).to eql 'Mauris purus urna, ultrices et suscipit ut, faucibus eget mauris.'
|
74
|
+
expect(posts[1].created_at).to eql Time.new(2015, 12, 11, 11, 32, 0)
|
75
|
+
expect(posts[2].id).to eql 16
|
76
|
+
expect(posts[2].title).to eql 'Vestibulum Commodo'
|
77
|
+
expect(posts[2].body).to eql 'Vestibulum commodo fringilla suscipit.'
|
78
|
+
expect(posts[2].created_at).to eql Time.new(2016, 2, 6, 18, 45, 0)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'with connection_options[:params]' do
|
84
|
+
let!(:expected_request) do
|
85
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
86
|
+
mock_request.with(query: { pseudonym: 'pseudonym' }, body: nil, headers: expected_default_headers)
|
87
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
88
|
+
mock_request
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'performs the correct HTTP GET request' do
|
92
|
+
Post.all(params: { pseudonym: 'pseudonym' })
|
93
|
+
expect(expected_request).to have_been_requested
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'with connection_options[:headers]' do
|
98
|
+
let!(:expected_request) do
|
99
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
100
|
+
mock_request.with(query: nil, body: nil, headers: expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
101
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
102
|
+
mock_request
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'performs the correct HTTP GET request' do
|
106
|
+
Post.all(headers: { 'X-Pseudonym' => 'pseudonym' })
|
107
|
+
expect(expected_request).to have_been_requested
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'with a 404 response' do
|
112
|
+
let!(:expected_request) do
|
113
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
114
|
+
mock_request.with(query: { pseudonym: 'pseudonym' }, body: nil, headers: expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
115
|
+
mock_request.to_return(status: 404)
|
116
|
+
mock_request
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'raises the not found error' do
|
120
|
+
expect { Post.all(params: { pseudonym: 'pseudonym' }, headers: { 'X-Pseudonym' => 'pseudonym' }) }.to raise_error RemoteResource::HTTPNotFound
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'adds metadata to the raised error' do
|
124
|
+
begin
|
125
|
+
Post.all(params: { pseudonym: 'pseudonym' }, headers: { 'X-Pseudonym' => 'pseudonym' })
|
126
|
+
rescue RemoteResource::HTTPNotFound => error
|
127
|
+
aggregate_failures do
|
128
|
+
expect(error.message).to eql 'HTTP request failed for Post with response_code=404 with http_action=get with request_url=https://www.example.com/posts.json'
|
129
|
+
expect(error.request_url).to eql 'https://www.example.com/posts.json'
|
130
|
+
expect(error.response_code).to eql 404
|
131
|
+
expect(error.request_query).to eql(RemoteResource::Util.encode_params_to_query({ pseudonym: 'pseudonym' }))
|
132
|
+
expect(error.request_headers).to eql(expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe 'with a 500 response' do
|
139
|
+
let!(:expected_request) do
|
140
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
141
|
+
mock_request.with(query: { pseudonym: 'pseudonym' }, body: nil, headers: expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
142
|
+
mock_request.to_return(status: 500)
|
143
|
+
mock_request
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'raises the server error' do
|
147
|
+
expect { Post.all(params: { pseudonym: 'pseudonym' }, headers: { 'X-Pseudonym' => 'pseudonym' }) }.to raise_error RemoteResource::HTTPServerError
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'adds metadata to the raised error' do
|
151
|
+
begin
|
152
|
+
Post.all(params: { pseudonym: 'pseudonym' }, headers: { 'X-Pseudonym' => 'pseudonym' })
|
153
|
+
rescue RemoteResource::HTTPServerError => error
|
154
|
+
aggregate_failures do
|
155
|
+
expect(error.message).to eql 'HTTP request failed for Post with response_code=500 with http_action=get with request_url=https://www.example.com/posts.json'
|
156
|
+
expect(error.request_url).to eql 'https://www.example.com/posts.json'
|
157
|
+
expect(error.response_code).to eql 500
|
158
|
+
expect(error.request_query).to eql(RemoteResource::Util.encode_params_to_query({ pseudonym: 'pseudonym' }))
|
159
|
+
expect(error.request_headers).to eql(expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'connection_options[:collection_prefix] and connection_options[:collection_options]' do
|
4
|
+
|
5
|
+
class Post
|
6
|
+
include RemoteResource::Base
|
7
|
+
|
8
|
+
self.site = 'https://www.example.com'
|
9
|
+
self.collection = true
|
10
|
+
self.root_element = :data
|
11
|
+
|
12
|
+
attribute :title, String
|
13
|
+
attribute :body, String
|
14
|
+
attribute :featured, Boolean
|
15
|
+
attribute :created_at, Time
|
16
|
+
end
|
17
|
+
|
18
|
+
class Comment
|
19
|
+
include RemoteResource::Base
|
20
|
+
|
21
|
+
self.site = 'https://www.example.com'
|
22
|
+
self.collection = true
|
23
|
+
self.collection_prefix = '/posts/:post_id'
|
24
|
+
self.root_element = :data
|
25
|
+
|
26
|
+
attribute :body, String
|
27
|
+
attribute :commented_at, Time
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'connection_options[:collection_prefix] defined on class' do
|
31
|
+
let(:response_body) do
|
32
|
+
{
|
33
|
+
data: {
|
34
|
+
id: 18,
|
35
|
+
body: 'Very interesting comment',
|
36
|
+
commented_at: Time.new(2016, 12, 8, 11, 38, 0)
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
let!(:expected_request) do
|
42
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts/12/comments/18.json')
|
43
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
44
|
+
mock_request
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'performs the correct HTTP GET request' do
|
48
|
+
Comment.find(18, collection_options: { post_id: 12 })
|
49
|
+
expect(expected_request).to have_been_requested
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'builds the correct resource' do
|
53
|
+
comment = Comment.find(18, collection_options: { post_id: 12 })
|
54
|
+
|
55
|
+
aggregate_failures do
|
56
|
+
expect(comment.id).to eql 18
|
57
|
+
expect(comment.body).to eql 'Very interesting comment'
|
58
|
+
expect(comment.commented_at).to eql Time.new(2016, 12, 8, 11, 38, 0)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'connection_options[:collection_prefix] given as argument' do
|
64
|
+
let(:response_body) do
|
65
|
+
{
|
66
|
+
data: {
|
67
|
+
id: 12,
|
68
|
+
title: 'Lorem Ipsum',
|
69
|
+
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
70
|
+
featured: true,
|
71
|
+
created_at: Time.new(2015, 10, 4, 9, 30, 0),
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
let!(:expected_request) do
|
77
|
+
mock_request = stub_request(:get, 'https://www.example.com/users/450/posts/12.json')
|
78
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
79
|
+
mock_request
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'performs the correct HTTP GET request' do
|
83
|
+
Post.find(12, collection_prefix: '/users/:user_id', collection_options: { user_id: 450 })
|
84
|
+
expect(expected_request).to have_been_requested
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'builds the correct resource' do
|
88
|
+
post = Post.find(12, collection_prefix: '/users/:user_id', collection_options: { user_id: 450 })
|
89
|
+
|
90
|
+
aggregate_failures do
|
91
|
+
expect(post.id).to eql 12
|
92
|
+
expect(post.title).to eql 'Lorem Ipsum'
|
93
|
+
expect(post.body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
94
|
+
expect(post.created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|