acfs 0.33.1.1.b285 → 0.34.0
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.
- checksums.yaml +5 -13
- data/CHANGELOG.md +6 -0
- data/doc/file.README.html +398 -0
- data/lib/acfs/model/persistence.rb +1 -1
- data/lib/acfs/parameter_decoder.rb +37 -0
- data/lib/acfs/version.rb +2 -2
- data/spec/acfs/model/query_methods_spec.rb +32 -32
- data/spec/spec_helper.rb +0 -2
- metadata +21 -18
checksums.yaml
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
|
|
5
|
-
data.tar.gz: !binary |-
|
|
6
|
-
NjM5MzYwYTAwMmIzZDVjY2IyZDk5NmVkZDA0MGZiZjg2NjdjNTRlNg==
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 79f96815f2139c2a96c6c79a311904567483e720
|
|
4
|
+
data.tar.gz: 0dd9f4379210854cda16b5e6e70868c8201d093d
|
|
7
5
|
SHA512:
|
|
8
|
-
metadata.gz:
|
|
9
|
-
|
|
10
|
-
ZWVmYzc0YmNkNGM4OGZmMTBiYTFkOGQ5ODc4NDdlMDM0MjU1MTNhMTFkNTFk
|
|
11
|
-
NTQxNGRlMDgyMGUwNzcxNmRlMmRkOGRlOGEwYjI5NmVlNWYyZTc=
|
|
12
|
-
data.tar.gz: !binary |-
|
|
13
|
-
ZTg2ZTRmZDQyOTg0MmI2MDRmNmNiMTRjY2MyYTlhNjdkMzdjNmViYjMwNzk3
|
|
14
|
-
MmYxZGI3YjY5YmM2ZTU0NTg5YjAxODZhN2U5MzAyMTc4MjY1YWE5MTljM2I3
|
|
15
|
-
OTA0ZWI1MmJiNmU1YzE5MDkxYjM2ODkwMWQ2ZDZlZTJlMjRjMTg=
|
|
6
|
+
metadata.gz: 4d39d8dcb64e34c8f9ed4962c417958f2de27a811a8caf039cec4ebf2c892fda5839fe17ebfef515e75eab8482bb13976a1c512ff938ef460e9cfd3a98b264ab
|
|
7
|
+
data.tar.gz: 0d054784e48f8c4e9fd7973fb3d8abaf333066960353d653fff930933b0ad041f8ae6d724eaccf8ec54ad37d98b727e8914ebf1b61053072c19368c6e27eff29
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.34.0
|
|
4
|
+
|
|
5
|
+
* Add support for will_paginate view helper used with `Acfs::Collection`s
|
|
6
|
+
* Add support for pagination header added by [paginate-responder](https://github.com/jgraichen/paginate-responder)
|
|
7
|
+
* Improve `Resource#new?` detection by using `loaded?` instead of presence of `:id` attribute
|
|
8
|
+
|
|
3
9
|
## 0.33.0
|
|
4
10
|
|
|
5
11
|
* Do not raise errors on unknown attributes by default, add :unknown option.
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
6
|
+
<title>
|
|
7
|
+
File: README
|
|
8
|
+
|
|
9
|
+
— Documentation by YARD 0.8.7.3
|
|
10
|
+
|
|
11
|
+
</title>
|
|
12
|
+
|
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
|
14
|
+
|
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
|
16
|
+
|
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
|
18
|
+
hasFrames = window.top.frames.main ? true : false;
|
|
19
|
+
relpath = '';
|
|
20
|
+
framesUrl = "frames.html#!" + escape(window.location.href);
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
|
25
|
+
|
|
26
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
</head>
|
|
30
|
+
<body>
|
|
31
|
+
<div id="header">
|
|
32
|
+
<div id="menu">
|
|
33
|
+
|
|
34
|
+
<a href="_index.html">Index</a> »
|
|
35
|
+
<span class="title">File: README</span>
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
<div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div id="search">
|
|
42
|
+
|
|
43
|
+
<a class="full_list_link" id="class_list_link"
|
|
44
|
+
href="class_list.html">
|
|
45
|
+
Class List
|
|
46
|
+
</a>
|
|
47
|
+
|
|
48
|
+
<a class="full_list_link" id="method_list_link"
|
|
49
|
+
href="method_list.html">
|
|
50
|
+
Method List
|
|
51
|
+
</a>
|
|
52
|
+
|
|
53
|
+
<a class="full_list_link" id="file_list_link"
|
|
54
|
+
href="file_list.html">
|
|
55
|
+
File List
|
|
56
|
+
</a>
|
|
57
|
+
|
|
58
|
+
</div>
|
|
59
|
+
<div class="clear"></div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<iframe id="search_frame"></iframe>
|
|
63
|
+
|
|
64
|
+
<div id="content"><div id='filecontents'><h1>Acfs - <em>API client for services</em></h1>
|
|
65
|
+
|
|
66
|
+
<p><a href="http://badge.fury.io/rb/acfs"><img src="https://badge.fury.io/rb/acfs.png" alt="Gem Version"></a>
|
|
67
|
+
<a href="https://travis-ci.org/jgraichen/acfs"><img src="https://travis-ci.org/jgraichen/acfs.png?branch=master" alt="Build Status"></a>
|
|
68
|
+
<a href="https://coveralls.io/r/jgraichen/acfs"><img src="https://coveralls.io/repos/jgraichen/acfs/badge.png?branch=master" alt="Coverage Status"></a>
|
|
69
|
+
<a href="https://codeclimate.com/github/jgraichen/acfs"><img src="https://codeclimate.com/github/jgraichen/acfs.png" alt="Code Climate"></a>
|
|
70
|
+
<a href="https://gemnasium.com/jgraichen/acfs"><img src="https://gemnasium.com/jgraichen/acfs.png" alt="Dependency Status"></a>
|
|
71
|
+
<a href="http://rubydoc.info/github/jgraichen/acfs/master/frames"><img src="http://b.repl.ca/v1/rubydoc-here-blue.png" alt="RubyDoc Documentation"></a></p>
|
|
72
|
+
|
|
73
|
+
<p>Acfs is a library to develop API client libraries for single services within a larger service oriented application.</p>
|
|
74
|
+
|
|
75
|
+
<p>Acfs covers model and service abstraction, convenient query and filter methods, full middleware stack for pre-processing requests and responses on a per service level and automatic request queuing and parallel processing. See Usage for more.</p>
|
|
76
|
+
|
|
77
|
+
<h2>Installation</h2>
|
|
78
|
+
|
|
79
|
+
<p>Add this line to your application's Gemfile:</p>
|
|
80
|
+
|
|
81
|
+
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>acfs</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>~> 0.21.0</span><span class='tstring_end'>'</span></span>
|
|
82
|
+
</code></pre>
|
|
83
|
+
|
|
84
|
+
<p><strong>Note:</strong> Acfs is under development. I'll try to avoid changes to the public API but internal APIs may change quite often.</p>
|
|
85
|
+
|
|
86
|
+
<p>And then execute:</p>
|
|
87
|
+
|
|
88
|
+
<pre class="code ruby"><code class="ruby">> bundle
|
|
89
|
+
</code></pre>
|
|
90
|
+
|
|
91
|
+
<p>Or install it yourself as:</p>
|
|
92
|
+
|
|
93
|
+
<pre class="code ruby"><code class="ruby">> gem install acfs
|
|
94
|
+
</code></pre>
|
|
95
|
+
|
|
96
|
+
<h2>Usage</h2>
|
|
97
|
+
|
|
98
|
+
<p>First you need to define your service(s):</p>
|
|
99
|
+
|
|
100
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>UserService</span> <span class='op'><</span> <span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Service</span>
|
|
101
|
+
<span class='kw'>self</span><span class='period'>.</span><span class='id identifier rubyid_base_url'>base_url</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>http://users.myapp.org</span><span class='tstring_end'>'</span></span>
|
|
102
|
+
|
|
103
|
+
<span class='comment'># You can configure middlewares you want to use for the service here.
|
|
104
|
+
</span> <span class='comment'># Each service has it own middleware stack.
|
|
105
|
+
</span> <span class='comment'>#
|
|
106
|
+
</span> <span class='id identifier rubyid_use'>use</span> <span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Middleware</span><span class='op'>::</span><span class='const'>JsonDecoder</span>
|
|
107
|
+
<span class='id identifier rubyid_use'>use</span> <span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Middleware</span><span class='op'>::</span><span class='const'>MessagePackDecoder</span>
|
|
108
|
+
<span class='kw'>end</span>
|
|
109
|
+
</code></pre>
|
|
110
|
+
|
|
111
|
+
<p>This specifies where the <code>UserService</code> is located. You can now create some models representing resources served by the <code>UserService</code>.</p>
|
|
112
|
+
|
|
113
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>User</span> <span class='op'><</span> <span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Resource</span>
|
|
114
|
+
<span class='id identifier rubyid_service'>service</span> <span class='const'>UserService</span> <span class='comment'># Associate `User` model with `UserService`.
|
|
115
|
+
</span>
|
|
116
|
+
<span class='comment'># Define model attributes and types
|
|
117
|
+
</span> <span class='comment'># Types are needed to parse and generate request and response payload.
|
|
118
|
+
</span>
|
|
119
|
+
<span class='id identifier rubyid_attribute'>attribute</span> <span class='symbol'>:id</span><span class='comma'>,</span> <span class='symbol'>:uuid</span> <span class='comment'># Types can be classes or symbols.
|
|
120
|
+
</span> <span class='comment'># Symbols will be used to load a class from `Acfs::Model::Attributes` namespace.
|
|
121
|
+
</span> <span class='comment'># Eg. `:uuid` will load class `Acfs::Model::Attributes::Uuid`.
|
|
122
|
+
</span>
|
|
123
|
+
<span class='id identifier rubyid_attribute'>attribute</span> <span class='symbol'>:name</span><span class='comma'>,</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Anonymous</span><span class='tstring_end'>'</span></span>
|
|
124
|
+
<span class='id identifier rubyid_attribute'>attribute</span> <span class='symbol'>:age</span><span class='comma'>,</span> <span class='op'>::</span><span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Model</span><span class='op'>::</span><span class='const'>Attributes</span><span class='op'>::</span><span class='const'>Integer</span> <span class='comment'># Or use :integer
|
|
125
|
+
</span>
|
|
126
|
+
<span class='kw'>end</span>
|
|
127
|
+
</code></pre>
|
|
128
|
+
|
|
129
|
+
<p>The service and model classes can be shipped as a gem or git submodule to be included by the frontend application(s).</p>
|
|
130
|
+
|
|
131
|
+
<p>You can use the model there:</p>
|
|
132
|
+
|
|
133
|
+
<pre class="code ruby"><code class="ruby"><span class='ivar'>@user</span> <span class='op'>=</span> <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span> <span class='int'>14</span>
|
|
134
|
+
|
|
135
|
+
<span class='ivar'>@user</span><span class='period'>.</span><span class='id identifier rubyid_loaded?'>loaded?</span> <span class='comment'>#=> false
|
|
136
|
+
</span>
|
|
137
|
+
<span class='const'>Acfs</span><span class='period'>.</span><span class='id identifier rubyid_run'>run</span> <span class='comment'># This will run all queued request as parallel as possible.
|
|
138
|
+
</span> <span class='comment'># For @user the following URL will be requested:
|
|
139
|
+
</span> <span class='comment'># `http://users.myapp.org/users/14`
|
|
140
|
+
</span>
|
|
141
|
+
<span class='ivar'>@model</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span> <span class='comment'># => "..."
|
|
142
|
+
</span>
|
|
143
|
+
<span class='ivar'>@users</span> <span class='op'>=</span> <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span>
|
|
144
|
+
<span class='ivar'>@users</span><span class='period'>.</span><span class='id identifier rubyid_loaded?'>loaded?</span> <span class='comment'>#=> false
|
|
145
|
+
</span>
|
|
146
|
+
<span class='const'>Acfs</span><span class='period'>.</span><span class='id identifier rubyid_run'>run</span> <span class='comment'># Will request `http://users.myapp.org/users`
|
|
147
|
+
</span>
|
|
148
|
+
<span class='ivar'>@users</span> <span class='comment'>#=> [<User>, ...]
|
|
149
|
+
</span></code></pre>
|
|
150
|
+
|
|
151
|
+
<p>If you need multiple resources or dependent resources first define a "plan" how they can be loaded:</p>
|
|
152
|
+
|
|
153
|
+
<pre class="code ruby"><code class="ruby"><span class='ivar'>@user</span> <span class='op'>=</span> <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span><span class='lparen'>(</span><span class='int'>5</span><span class='rparen'>)</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_user'>user</span><span class='op'>|</span>
|
|
154
|
+
<span class='comment'># Block will be executed right after user with id 5 is loaded
|
|
155
|
+
</span>
|
|
156
|
+
<span class='comment'># You can load additional resources also from other services
|
|
157
|
+
</span> <span class='comment'># Eg. fetch comments from `CommentSerivce`. The line below will
|
|
158
|
+
</span> <span class='comment'># load comments from `http://comments.myapp.org/comments?user=5`
|
|
159
|
+
</span> <span class='ivar'>@comments</span> <span class='op'>=</span> <span class='const'>Comment</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span> <span class='label'>user:</span> <span class='id identifier rubyid_user'>user</span><span class='period'>.</span><span class='id identifier rubyid_id'>id</span>
|
|
160
|
+
|
|
161
|
+
<span class='comment'># You can load multiple resources in parallel if you have multiple
|
|
162
|
+
</span> <span class='comment'># ids.
|
|
163
|
+
</span> <span class='ivar'>@friends</span> <span class='op'>=</span> <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span> <span class='int'>1</span><span class='comma'>,</span> <span class='int'>4</span><span class='comma'>,</span> <span class='int'>10</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_friends'>friends</span><span class='op'>|</span>
|
|
164
|
+
<span class='comment'># This block will be executed when all friends are loaded.
|
|
165
|
+
</span> <span class='comment'># [ ... ]
|
|
166
|
+
</span> <span class='kw'>end</span>
|
|
167
|
+
<span class='kw'>end</span>
|
|
168
|
+
|
|
169
|
+
<span class='const'>Acfs</span><span class='period'>.</span><span class='id identifier rubyid_run'>run</span> <span class='comment'># This call will fire all request as parallel as possible.
|
|
170
|
+
</span> <span class='comment'># The sequence above would look similar to:
|
|
171
|
+
</span> <span class='comment'>#
|
|
172
|
+
</span> <span class='comment'># Start Fin
|
|
173
|
+
</span> <span class='comment'># |===================| `Acfs.run`
|
|
174
|
+
</span> <span class='comment'># |====| /users/5
|
|
175
|
+
</span> <span class='comment'># | |==============| /comments?user=5
|
|
176
|
+
</span> <span class='comment'># | |======| /users/1
|
|
177
|
+
</span> <span class='comment'># | |=======| /users/4
|
|
178
|
+
</span> <span class='comment'># | |======| /users/10
|
|
179
|
+
</span>
|
|
180
|
+
<span class='comment'># Now we can access all resources:
|
|
181
|
+
</span>
|
|
182
|
+
<span class='ivar'>@user</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span> <span class='comment'># => "John
|
|
183
|
+
</span><span class='ivar'>@comments</span><span class='period'>.</span><span class='id identifier rubyid_size'>size</span> <span class='comment'># => 25
|
|
184
|
+
</span><span class='ivar'>@friends</span><span class='lbracket'>[</span><span class='int'>0</span><span class='rbracket'>]</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span> <span class='comment'># => "Miraculix"
|
|
185
|
+
</span></code></pre>
|
|
186
|
+
|
|
187
|
+
<p>Use <code>.find_by</code> to get first element only. <code>.find_by</code> will call the <code>index</code>-Action and return the first resource. Optionally passed params will be sent as <code>GET</code> parameters and can be used for filtering in the service's controller.
|
|
188
|
+
```ruby
|
|
189
|
+
@user = User.find_by age: 24</p>
|
|
190
|
+
|
|
191
|
+
<p>Acfs.run # Will request <code>http://users.myapp.org/users?age=24</code></p>
|
|
192
|
+
|
|
193
|
+
<p>@user # Contains the first user object returned by the index action
|
|
194
|
+
``<code>
|
|
195
|
+
If no object can be found,</code>.find_by<code>will return</code>nil<code>. The optional callback will then be called with</code>nil<code>as parameter. Use</code>.find_by!<code>to raise an</code>Acfs::ResourceNotFound<code>exception if no object can be found.</code>.find_by!` will only invoke the optional callback if an object was successfully loaded.</p>
|
|
196
|
+
|
|
197
|
+
<p>Acfs has basic update support using <code>PUT</code> requests:</p>
|
|
198
|
+
|
|
199
|
+
<pre class="code ruby"><code class="ruby"><span class='ivar'>@user</span> <span class='op'>=</span> <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span> <span class='int'>5</span>
|
|
200
|
+
<span class='ivar'>@user</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Bob</span><span class='tstring_end'>"</span></span>
|
|
201
|
+
|
|
202
|
+
<span class='ivar'>@user</span><span class='period'>.</span><span class='id identifier rubyid_changed?'>changed?</span> <span class='comment'># => true
|
|
203
|
+
</span><span class='ivar'>@user</span><span class='period'>.</span><span class='id identifier rubyid_persisted?'>persisted?</span> <span class='comment'># => false
|
|
204
|
+
</span>
|
|
205
|
+
<span class='ivar'>@user</span><span class='period'>.</span><span class='id identifier rubyid_save'>save</span> <span class='comment'># Or .save!
|
|
206
|
+
</span> <span class='comment'># Will PUT new resource to service synchronously.
|
|
207
|
+
</span>
|
|
208
|
+
<span class='ivar'>@user</span><span class='period'>.</span><span class='id identifier rubyid_changed?'>changed?</span> <span class='comment'># => false
|
|
209
|
+
</span><span class='ivar'>@user</span><span class='period'>.</span><span class='id identifier rubyid_persisted?'>persisted?</span> <span class='comment'># => true
|
|
210
|
+
</span></code></pre>
|
|
211
|
+
|
|
212
|
+
<h2>Singleton resources</h2>
|
|
213
|
+
|
|
214
|
+
<p>Singletons can be used in Acfs by creating a new resource which inherits from <code>SingletonResource</code>:</p>
|
|
215
|
+
|
|
216
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>Single</span> <span class='op'><</span> <span class='const'>Acfs</span><span class='op'>::</span><span class='const'>SingletonResource</span>
|
|
217
|
+
<span class='id identifier rubyid_service'>service</span> <span class='const'>UserService</span> <span class='comment'># Associate `Single` model with `UserService`.
|
|
218
|
+
</span>
|
|
219
|
+
<span class='comment'># Define model attributes and types as with regular resources
|
|
220
|
+
</span>
|
|
221
|
+
<span class='id identifier rubyid_attribute'>attribute</span> <span class='symbol'>:name</span><span class='comma'>,</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Anonymous</span><span class='tstring_end'>'</span></span>
|
|
222
|
+
<span class='id identifier rubyid_attribute'>attribute</span> <span class='symbol'>:age</span><span class='comma'>,</span> <span class='symbol'>:integer</span>
|
|
223
|
+
|
|
224
|
+
<span class='kw'>end</span>
|
|
225
|
+
</code></pre>
|
|
226
|
+
|
|
227
|
+
<p>The following code explains the routing for singleton resource requests:</p>
|
|
228
|
+
|
|
229
|
+
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_my_single'>my_single</span> <span class='op'>=</span> <span class='const'>Single</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span>
|
|
230
|
+
<span class='id identifier rubyid_mysingle'>mysingle</span><span class='period'>.</span><span class='id identifier rubyid_save'>save</span> <span class='comment'># sends POST request to /single
|
|
231
|
+
</span>
|
|
232
|
+
<span class='id identifier rubyid_my_single'>my_single</span> <span class='op'>=</span> <span class='const'>Single</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span>
|
|
233
|
+
<span class='const'>Acfs</span><span class='period'>.</span><span class='id identifier rubyid_run'>run</span> <span class='comment'># sends GET request to /single
|
|
234
|
+
</span>
|
|
235
|
+
<span class='id identifier rubyid_my_single'>my_single</span><span class='period'>.</span><span class='id identifier rubyid_age'>age</span> <span class='op'>=</span> <span class='int'>28</span>
|
|
236
|
+
<span class='id identifier rubyid_my_single'>my_single</span><span class='period'>.</span><span class='id identifier rubyid_save'>save</span> <span class='comment'># sends PUT request to /single
|
|
237
|
+
</span>
|
|
238
|
+
<span class='id identifier rubyid_my_single'>my_single</span><span class='period'>.</span><span class='id identifier rubyid_delete'>delete</span> <span class='comment'># sends DELETE request to /single
|
|
239
|
+
</span></code></pre>
|
|
240
|
+
|
|
241
|
+
<p>You also can pass parameters to the find call, these will sent as GET params to the index action:</p>
|
|
242
|
+
|
|
243
|
+
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_my_single'>my_single</span> <span class='op'>=</span> <span class='const'>Single</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span> <span class='label'>name:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Max</span><span class='tstring_end'>'</span></span>
|
|
244
|
+
<span class='const'>Acfs</span><span class='period'>.</span><span class='id identifier rubyid_run'>run</span> <span class='comment'># sends GET request with param to /single?name=Max
|
|
245
|
+
</span></code></pre>
|
|
246
|
+
|
|
247
|
+
<h2>Resource Inheritance</h2>
|
|
248
|
+
|
|
249
|
+
<p>Acfs provides a resource inheritance similar to ActiveRecord Single Table Inheritance. If a
|
|
250
|
+
<code>type</code> attribute exists and is a valid subclass of your resource they will be converted
|
|
251
|
+
to you subclassed resources:</p>
|
|
252
|
+
|
|
253
|
+
<pre class="code ruby"><code class="ruby">class Computer < Acfs::Resource
|
|
254
|
+
...
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
class Pc < Computer end
|
|
258
|
+
class Mac < Computer end
|
|
259
|
+
</code></pre>
|
|
260
|
+
|
|
261
|
+
<p>With the following response on <code>GET /computers</code> the collection will contain the appropriate
|
|
262
|
+
subclass resources:</p>
|
|
263
|
+
|
|
264
|
+
<pre class="code json"><code class="json">[
|
|
265
|
+
{ "id": 5, "type": "Computer"},
|
|
266
|
+
{ "id": 6, "type": "Mac"},
|
|
267
|
+
{ "id": 8, "type": "Pc"}
|
|
268
|
+
]
|
|
269
|
+
</code></pre>
|
|
270
|
+
|
|
271
|
+
<pre class="code ruby"><code class="ruby"><span class='ivar'>@computers</span> <span class='op'>=</span> <span class='const'>Computer</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span>
|
|
272
|
+
|
|
273
|
+
<span class='const'>Acfs</span><span class='period'>.</span><span class='id identifier rubyid_run'>run</span>
|
|
274
|
+
|
|
275
|
+
<span class='ivar'>@computer</span><span class='lbracket'>[</span><span class='int'>0</span><span class='rbracket'>]</span><span class='period'>.</span><span class='id identifier rubyid_class'>class</span> <span class='comment'># => Computer
|
|
276
|
+
</span><span class='ivar'>@computer</span><span class='lbracket'>[</span><span class='int'>1</span><span class='rbracket'>]</span><span class='period'>.</span><span class='id identifier rubyid_class'>class</span> <span class='comment'># => Mac
|
|
277
|
+
</span><span class='ivar'>@computer</span><span class='lbracket'>[</span><span class='int'>2</span><span class='rbracket'>]</span><span class='period'>.</span><span class='id identifier rubyid_class'>class</span> <span class='comment'># => Pc
|
|
278
|
+
</span></code></pre>
|
|
279
|
+
|
|
280
|
+
<h2>Stubbing</h2>
|
|
281
|
+
|
|
282
|
+
<p>You can stub resources in applications using an Acfs service client:</p>
|
|
283
|
+
|
|
284
|
+
<pre class="code ruby"><code class="ruby"><span class='comment'># spec_helper.rb
|
|
285
|
+
</span>
|
|
286
|
+
<span class='comment'># This will enable stabs before each spec and clear internal state
|
|
287
|
+
</span><span class='comment'># after each spec.
|
|
288
|
+
</span><span class='id identifier rubyid_require'>require</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>acfs/rspec</span><span class='tstring_end'>'</span></span>
|
|
289
|
+
</code></pre>
|
|
290
|
+
|
|
291
|
+
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_before'>before</span> <span class='kw'>do</span>
|
|
292
|
+
<span class='ivar'>@stub</span> <span class='op'>=</span> <span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Stub</span><span class='period'>.</span><span class='id identifier rubyid_resource'>resource</span> <span class='const'>MyUser</span><span class='comma'>,</span> <span class='symbol'>:read</span><span class='comma'>,</span> <span class='label'>with:</span> <span class='lbrace'>{</span> <span class='label'>id:</span> <span class='int'>1</span> <span class='rbrace'>}</span><span class='comma'>,</span> <span class='label'>return:</span> <span class='lbrace'>{</span> <span class='label'>id:</span> <span class='int'>1</span><span class='comma'>,</span> <span class='label'>name:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>John Smith</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>age:</span> <span class='int'>32</span> <span class='rbrace'>}</span>
|
|
293
|
+
<span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Stub</span><span class='period'>.</span><span class='id identifier rubyid_resource'>resource</span> <span class='const'>MyUser</span><span class='comma'>,</span> <span class='symbol'>:read</span><span class='comma'>,</span> <span class='label'>with:</span> <span class='lbrace'>{</span> <span class='label'>id:</span> <span class='int'>2</span> <span class='rbrace'>}</span><span class='comma'>,</span> <span class='label'>raise:</span> <span class='symbol'>:not_found</span>
|
|
294
|
+
<span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Stub</span><span class='period'>.</span><span class='id identifier rubyid_resource'>resource</span> <span class='const'>Session</span><span class='comma'>,</span> <span class='symbol'>:create</span><span class='comma'>,</span> <span class='label'>with:</span> <span class='lbrace'>{</span> <span class='label'>ident:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>john@exmaple.org</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>password:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>s3cr3t</span><span class='tstring_end'>'</span></span> <span class='rbrace'>}</span><span class='comma'>,</span> <span class='label'>return:</span> <span class='lbrace'>{</span> <span class='label'>id:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>longhash</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>user:</span> <span class='int'>1</span> <span class='rbrace'>}</span>
|
|
295
|
+
<span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Stub</span><span class='period'>.</span><span class='id identifier rubyid_resource'>resource</span> <span class='const'>MyUser</span><span class='comma'>,</span> <span class='symbol'>:update</span><span class='comma'>,</span> <span class='label'>with:</span> <span class='id identifier rubyid_lambda'>lambda</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_op'>op</span><span class='op'>|</span> <span class='id identifier rubyid_op'>op</span><span class='period'>.</span><span class='id identifier rubyid_data'>data</span><span class='period'>.</span><span class='id identifier rubyid_include?'>include?</span> <span class='symbol'>:my_var</span> <span class='rbrace'>}</span><span class='comma'>,</span> <span class='label'>raise:</span> <span class='int'>400</span>
|
|
296
|
+
<span class='kw'>end</span>
|
|
297
|
+
|
|
298
|
+
<span class='id identifier rubyid_it'>it</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>should find user number one</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span>
|
|
299
|
+
<span class='id identifier rubyid_user'>user</span> <span class='op'>=</span> <span class='const'>MyUser</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span> <span class='int'>1</span>
|
|
300
|
+
<span class='const'>Acfs</span><span class='period'>.</span><span class='id identifier rubyid_run'>run</span>
|
|
301
|
+
|
|
302
|
+
<span class='id identifier rubyid_expect'>expect</span><span class='lparen'>(</span><span class='id identifier rubyid_user'>user</span><span class='period'>.</span><span class='id identifier rubyid_id'>id</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_to'>to</span> <span class='id identifier rubyid_be'>be</span> <span class='op'>==</span> <span class='int'>1</span>
|
|
303
|
+
<span class='id identifier rubyid_expect'>expect</span><span class='lparen'>(</span><span class='id identifier rubyid_user'>user</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_to'>to</span> <span class='id identifier rubyid_be'>be</span> <span class='op'>==</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>John Smith</span><span class='tstring_end'>'</span></span>
|
|
304
|
+
<span class='id identifier rubyid_expect'>expect</span><span class='lparen'>(</span><span class='id identifier rubyid_user'>user</span><span class='period'>.</span><span class='id identifier rubyid_age'>age</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_to'>to</span> <span class='id identifier rubyid_be'>be</span> <span class='op'>==</span> <span class='int'>32</span>
|
|
305
|
+
|
|
306
|
+
<span class='id identifier rubyid_expect'>expect</span><span class='lparen'>(</span><span class='ivar'>@stub</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_to'>to</span> <span class='id identifier rubyid_has_called'>has_called</span>
|
|
307
|
+
<span class='id identifier rubyid_expect'>expect</span><span class='lparen'>(</span><span class='ivar'>@stub</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_to_not'>to_not</span> <span class='id identifier rubyid_have_called'>have_called</span> <span class='int'>5</span><span class='period'>.</span><span class='id identifier rubyid_times'>times</span>
|
|
308
|
+
<span class='kw'>end</span>
|
|
309
|
+
|
|
310
|
+
<span class='id identifier rubyid_it'>it</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>should not find user number two</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span>
|
|
311
|
+
<span class='const'>MyUser</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span> <span class='int'>3</span>
|
|
312
|
+
|
|
313
|
+
<span class='id identifier rubyid_expect'>expect</span> <span class='lbrace'>{</span> <span class='const'>Acfs</span><span class='period'>.</span><span class='id identifier rubyid_run'>run</span> <span class='rbrace'>}</span><span class='period'>.</span><span class='id identifier rubyid_to'>to</span> <span class='id identifier rubyid_raise_error'>raise_error</span><span class='lparen'>(</span><span class='const'>Acfs</span><span class='op'>::</span><span class='const'>ResourceNotFound</span><span class='rparen'>)</span>
|
|
314
|
+
<span class='kw'>end</span>
|
|
315
|
+
|
|
316
|
+
<span class='id identifier rubyid_it'>it</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>should allow stub resource creation</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span>
|
|
317
|
+
<span class='id identifier rubyid_session'>session</span> <span class='op'>=</span> <span class='const'>Session</span><span class='period'>.</span><span class='id identifier rubyid_create!'>create!</span> <span class='label'>ident:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>john@exmaple.org</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>password:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>s3cr3t</span><span class='tstring_end'>'</span></span>
|
|
318
|
+
|
|
319
|
+
<span class='id identifier rubyid_expect'>expect</span><span class='lparen'>(</span><span class='id identifier rubyid_session'>session</span><span class='period'>.</span><span class='id identifier rubyid_id'>id</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_to'>to</span> <span class='id identifier rubyid_be'>be</span> <span class='op'>==</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>longhash</span><span class='tstring_end'>'</span></span>
|
|
320
|
+
<span class='id identifier rubyid_expect'>expect</span><span class='lparen'>(</span><span class='id identifier rubyid_session'>session</span><span class='period'>.</span><span class='id identifier rubyid_user'>user</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_to'>to</span> <span class='id identifier rubyid_be'>be</span> <span class='op'>==</span> <span class='int'>1</span>
|
|
321
|
+
<span class='kw'>end</span>
|
|
322
|
+
</code></pre>
|
|
323
|
+
|
|
324
|
+
<p>By default Acfs raises an error when a non stubbed resource should be requested. You can switch of the behavior:</p>
|
|
325
|
+
|
|
326
|
+
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_before'>before</span> <span class='kw'>do</span>
|
|
327
|
+
<span class='const'>Acfs</span><span class='op'>::</span><span class='const'>Stub</span><span class='period'>.</span><span class='id identifier rubyid_allow_requests'>allow_requests</span> <span class='op'>=</span> <span class='kw'>true</span>
|
|
328
|
+
<span class='kw'>end</span>
|
|
329
|
+
|
|
330
|
+
<span class='id identifier rubyid_it'>it</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>should find user number one</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span>
|
|
331
|
+
<span class='id identifier rubyid_user'>user</span> <span class='op'>=</span> <span class='const'>MyUser</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span> <span class='int'>1</span>
|
|
332
|
+
<span class='const'>Acfs</span><span class='period'>.</span><span class='id identifier rubyid_run'>run</span> <span class='comment'># Would have raised Acfs::RealRequestNotAllowedError
|
|
333
|
+
</span> <span class='comment'># Will run real request to user service instead.
|
|
334
|
+
</span><span class='kw'>end</span>
|
|
335
|
+
</code></pre>
|
|
336
|
+
|
|
337
|
+
<h2>Roadmap</h2>
|
|
338
|
+
|
|
339
|
+
<ul>
|
|
340
|
+
<li>Update
|
|
341
|
+
|
|
342
|
+
<ul>
|
|
343
|
+
<li>Better new? detection eg. storing ETag from request resources.</li>
|
|
344
|
+
<li>Use PATCH for with only changed attributes and <code>If-Unmodifed-Since</code>
|
|
345
|
+
and <code>If-Match</code> header fields if resource was surly loaded from service
|
|
346
|
+
and not created with an id (e.g <code>User.new id: 5, name: "john"</code>).</li>
|
|
347
|
+
<li>Conflict detection (ETag / If-Unmodified-Since)</li>
|
|
348
|
+
</ul></li>
|
|
349
|
+
<li>High level features
|
|
350
|
+
|
|
351
|
+
<ul>
|
|
352
|
+
<li>Support for custom mime types on client and server side. (<code>application/vnd.myservice.user.v2+msgpack</code>)</li>
|
|
353
|
+
<li>Server side components
|
|
354
|
+
|
|
355
|
+
<ul>
|
|
356
|
+
<li>Reusing model definitions for generating responses?</li>
|
|
357
|
+
<li>Rails responders providing REST operations with integrated ETag,
|
|
358
|
+
Modified Headers, conflict detection, ...</li>
|
|
359
|
+
</ul></li>
|
|
360
|
+
<li>Pagination? Filtering? (If service API provides such features.)</li>
|
|
361
|
+
</ul></li>
|
|
362
|
+
<li>Documentation</li>
|
|
363
|
+
</ul>
|
|
364
|
+
|
|
365
|
+
<h2>Contributing</h2>
|
|
366
|
+
|
|
367
|
+
<ol>
|
|
368
|
+
<li>Fork it</li>
|
|
369
|
+
<li>Create your feature branch (<code>git checkout -b my-new-feature</code>)</li>
|
|
370
|
+
<li>Add specs for your feature</li>
|
|
371
|
+
<li>Implement your feature</li>
|
|
372
|
+
<li>Commit your changes (<code>git commit -am 'Add some feature'</code>)</li>
|
|
373
|
+
<li>Push to the branch (<code>git push origin my-new-feature</code>)</li>
|
|
374
|
+
<li>Create new Pull Request</li>
|
|
375
|
+
</ol>
|
|
376
|
+
|
|
377
|
+
<h2>Contributors</h2>
|
|
378
|
+
|
|
379
|
+
<ul>
|
|
380
|
+
<li><a href="https://github.com/nicolas-fricke">Nicolas Fricke</a></li>
|
|
381
|
+
<li><a href="https://github.com/tino-junge">Tino Junge</a></li>
|
|
382
|
+
</ul>
|
|
383
|
+
|
|
384
|
+
<h2>License</h2>
|
|
385
|
+
|
|
386
|
+
<p>MIT License</p>
|
|
387
|
+
|
|
388
|
+
<p>Copyright (c) 2013 Jan Graichen. MIT license, see LICENSE for more details.</p>
|
|
389
|
+
</div></div>
|
|
390
|
+
|
|
391
|
+
<div id="footer">
|
|
392
|
+
Generated on Fri Mar 7 20:03:40 2014 by
|
|
393
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
394
|
+
0.8.7.3 (ruby-2.1.1).
|
|
395
|
+
</div>
|
|
396
|
+
|
|
397
|
+
</body>
|
|
398
|
+
</html>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Acfs::ParameterDecoder
|
|
2
|
+
|
|
3
|
+
module Functions
|
|
4
|
+
def self.deep_decode(hash)
|
|
5
|
+
return hash unless hash.is_a? Hash
|
|
6
|
+
|
|
7
|
+
hash.each_pair do |key, value|
|
|
8
|
+
if value.is_a? Hash
|
|
9
|
+
deep_decode(value)
|
|
10
|
+
hash[key] = decode_typhoeus_array(value)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.decode_typhoeus_array(hash)
|
|
16
|
+
if typhoeus_encoded? hash
|
|
17
|
+
hash.inject([]) do |memo, (key, val)|
|
|
18
|
+
memo[Integer(key)] = val
|
|
19
|
+
memo
|
|
20
|
+
end
|
|
21
|
+
else
|
|
22
|
+
hash
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.typhoeus_encoded?(hash)
|
|
27
|
+
return false if hash.empty?
|
|
28
|
+
self.keys.sort == (0...hash.keys.size).map { |i| i.to_s }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.included(base)
|
|
33
|
+
base.send :before_filter do
|
|
34
|
+
Functions.deep_decode params
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/acfs/version.rb
CHANGED
|
@@ -8,10 +8,10 @@ describe Acfs::Model::QueryMethods do
|
|
|
8
8
|
context 'with successful response' do
|
|
9
9
|
before do
|
|
10
10
|
stub_request(:get, 'http://users.example.org/users/1').to_return response({id: 1, name: 'Anon', age: 12, born_at: 'Berlin'})
|
|
11
|
-
stub_request(:get, 'http://users.example.org/users/2').to_return response({id: 2, type: 'Customer', name: 'Clare Customer', age: 24
|
|
11
|
+
stub_request(:get, 'http://users.example.org/users/2').to_return response({id: 2, type: 'Customer', name: 'Clare Customer', age: 24})
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
let(:action) { lambda{|cb=nil| model.find 1, &cb } }
|
|
14
|
+
let(:action) { lambda { |cb=nil| model.find 1, &cb } }
|
|
15
15
|
it_behaves_like 'a query method with multi-callback support'
|
|
16
16
|
|
|
17
17
|
it 'should load a single remote resource' do
|
|
@@ -19,7 +19,7 @@ describe Acfs::Model::QueryMethods do
|
|
|
19
19
|
Acfs.run
|
|
20
20
|
|
|
21
21
|
expect(user.attributes).to eq(
|
|
22
|
-
|
|
22
|
+
{id: 1, name: 'Anon', age: 12, born_at: 'Berlin'}.stringify_keys)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
context 'with resource type inheritance' do
|
|
@@ -40,7 +40,7 @@ describe Acfs::Model::QueryMethods do
|
|
|
40
40
|
|
|
41
41
|
context 'with 404 response' do
|
|
42
42
|
before do
|
|
43
|
-
stub_request(:get, 'http://users.example.org/users/1').to_return response({
|
|
43
|
+
stub_request(:get, 'http://users.example.org/users/1').to_return response({error: 'not found'}, status: 404)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
it 'should raise a NotFound error' do
|
|
@@ -69,10 +69,10 @@ describe Acfs::Model::QueryMethods do
|
|
|
69
69
|
|
|
70
70
|
context 'with multiple ids' do
|
|
71
71
|
before do
|
|
72
|
-
stub_request(:get, 'http://users.example.org/users/1').to_return response({
|
|
73
|
-
stub_request(:get, 'http://users.example.org/users/2').to_return response({
|
|
74
|
-
stub_request(:get, 'http://users.example.org/users/3').to_return response({
|
|
75
|
-
stub_request(:get, 'http://users.example.org/users/4').to_return response({
|
|
72
|
+
stub_request(:get, 'http://users.example.org/users/1').to_return response({id: 1, name: 'Anon', age: 12})
|
|
73
|
+
stub_request(:get, 'http://users.example.org/users/2').to_return response({id: 2, name: 'Johnny', age: 42})
|
|
74
|
+
stub_request(:get, 'http://users.example.org/users/3').to_return response({id: 3, type: 'Customer', name: 'Anon', age: 12})
|
|
75
|
+
stub_request(:get, 'http://users.example.org/users/4').to_return response({id: 4, name: 'Johnny', age: 42})
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
context 'with successful response' do
|
|
@@ -81,12 +81,12 @@ describe Acfs::Model::QueryMethods do
|
|
|
81
81
|
Acfs.run
|
|
82
82
|
|
|
83
83
|
expect(users.size).to be == 2
|
|
84
|
-
expect(users[0].attributes).to be == {
|
|
85
|
-
expect(users[1].attributes).to be == {
|
|
84
|
+
expect(users[0].attributes).to be == {id: 1, name: 'Anon', age: 12}.stringify_keys
|
|
85
|
+
expect(users[1].attributes).to be == {id: 2, name: 'Johnny', age: 42}.stringify_keys
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
it 'should invoke callback after all models are loaded' do
|
|
89
|
-
proc = Proc.new {
|
|
89
|
+
proc = Proc.new {}
|
|
90
90
|
expect(proc).to receive(:call) do |users|
|
|
91
91
|
expect(users).to be === @users
|
|
92
92
|
expect(users.size).to be == 2
|
|
@@ -98,8 +98,8 @@ describe Acfs::Model::QueryMethods do
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
it 'should invoke multiple callback after all models are loaded' do
|
|
101
|
-
proc1 = Proc.new {
|
|
102
|
-
proc2 = Proc.new {
|
|
101
|
+
proc1 = Proc.new {}
|
|
102
|
+
proc2 = Proc.new {}
|
|
103
103
|
expect(proc1).to receive(:call) do |users|
|
|
104
104
|
expect(users).to be === @users
|
|
105
105
|
expect(users.size).to be == 2
|
|
@@ -127,7 +127,7 @@ describe Acfs::Model::QueryMethods do
|
|
|
127
127
|
|
|
128
128
|
context 'with one 404 response' do
|
|
129
129
|
before do
|
|
130
|
-
stub_request(:get, 'http://users.example.org/users/1').to_return response({
|
|
130
|
+
stub_request(:get, 'http://users.example.org/users/1').to_return response({error: 'not found'}, status: 404)
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
it 'should raise resource not found error' do
|
|
@@ -144,12 +144,12 @@ describe Acfs::Model::QueryMethods do
|
|
|
144
144
|
let(:pc) { PC }
|
|
145
145
|
let(:mac) { Mac }
|
|
146
146
|
before do
|
|
147
|
-
stub_request(:get, 'http://computers.example.org/computers').to_return response([{
|
|
147
|
+
stub_request(:get, 'http://computers.example.org/computers').to_return response([{id: 1, type: 'PC'}, {id: 2, type: 'Computer'}, {id: 3, type: 'Mac'}])
|
|
148
148
|
end
|
|
149
149
|
|
|
150
150
|
it 'should invoke multiple callback after all models are loaded' do
|
|
151
|
-
proc1 = Proc.new {
|
|
152
|
-
proc2 = Proc.new {
|
|
151
|
+
proc1 = Proc.new {}
|
|
152
|
+
proc2 = Proc.new {}
|
|
153
153
|
expect(proc1).to receive(:call) do |computers|
|
|
154
154
|
expect(computers).to be === @computers
|
|
155
155
|
expect(computers.size).to be == 3
|
|
@@ -191,21 +191,21 @@ describe Acfs::Model::QueryMethods do
|
|
|
191
191
|
|
|
192
192
|
context 'with another resource as type instead' do
|
|
193
193
|
before do
|
|
194
|
-
stub_request(:get, 'http://computers.example.org/computers').to_return response([{
|
|
194
|
+
stub_request(:get, 'http://computers.example.org/computers').to_return response([{id: 1, type: 'MyUser'}, {id: 2, type: 'Computer'}, {id: 3, type: 'Mac'}])
|
|
195
195
|
end
|
|
196
196
|
it_behaves_like 'with invalid type'
|
|
197
197
|
end
|
|
198
198
|
|
|
199
199
|
context 'with a random string as type instead' do
|
|
200
200
|
before do
|
|
201
|
-
stub_request(:get, 'http://computers.example.org/computers').to_return response([{
|
|
201
|
+
stub_request(:get, 'http://computers.example.org/computers').to_return response([{id: 1, type: 'PC'}, {id: 2, type: 'noValidType'}, {id: 3, type: 'Mac'}])
|
|
202
202
|
end
|
|
203
203
|
it_behaves_like 'with invalid type'
|
|
204
204
|
end
|
|
205
205
|
|
|
206
206
|
context 'with a non-string as type instead' do
|
|
207
207
|
before do
|
|
208
|
-
stub_request(:get, 'http://computers.example.org/computers').to_return response([{
|
|
208
|
+
stub_request(:get, 'http://computers.example.org/computers').to_return response([{id: 1, type: 'PC'}, {id: 2, type: 'Computer'}, {id: 3, type: 42}])
|
|
209
209
|
end
|
|
210
210
|
it_behaves_like 'with invalid type'
|
|
211
211
|
end
|
|
@@ -239,7 +239,7 @@ describe Acfs::Model::QueryMethods do
|
|
|
239
239
|
before { stub_request(:get, 'http://users.example.org/users?age=24').to_return response([{id: 1, name: 'Mike', age: 24}, {id: 4, type: 'Maria', age: 24}, {id: 7, type: 'James', age: 24}]) }
|
|
240
240
|
|
|
241
241
|
it 'should invoke callback after model is loaded' do
|
|
242
|
-
proc = Proc.new {
|
|
242
|
+
proc = Proc.new {}
|
|
243
243
|
|
|
244
244
|
expect(proc).to receive(:call) do |user|
|
|
245
245
|
expect(user).to eql @user.__getobj__
|
|
@@ -252,8 +252,8 @@ describe Acfs::Model::QueryMethods do
|
|
|
252
252
|
end
|
|
253
253
|
|
|
254
254
|
it 'should invoke multiple callbacks after model is loaded' do
|
|
255
|
-
proc1 = Proc.new {
|
|
256
|
-
proc2 = Proc.new {
|
|
255
|
+
proc1 = Proc.new {}
|
|
256
|
+
proc2 = Proc.new {}
|
|
257
257
|
|
|
258
258
|
expect(proc1).to receive(:call) do |user|
|
|
259
259
|
expect(user).to eql @user.__getobj__
|
|
@@ -282,7 +282,7 @@ describe Acfs::Model::QueryMethods do
|
|
|
282
282
|
let(:model) { Single }
|
|
283
283
|
|
|
284
284
|
it '.find_by should not be defined' do
|
|
285
|
-
expect{ model.find_by }.to raise_error NoMethodError
|
|
285
|
+
expect { model.find_by }.to raise_error NoMethodError
|
|
286
286
|
end
|
|
287
287
|
end
|
|
288
288
|
end
|
|
@@ -292,7 +292,7 @@ describe Acfs::Model::QueryMethods do
|
|
|
292
292
|
it_behaves_like 'find_by'
|
|
293
293
|
|
|
294
294
|
context 'standard resource' do
|
|
295
|
-
let(:model){ MyUser }
|
|
295
|
+
let(:model) { MyUser }
|
|
296
296
|
let!(:user) { model.send described_method, age: 24 }
|
|
297
297
|
subject { Acfs.run; user }
|
|
298
298
|
|
|
@@ -302,7 +302,7 @@ describe Acfs::Model::QueryMethods do
|
|
|
302
302
|
it { should be_nil }
|
|
303
303
|
|
|
304
304
|
it 'should invoke callback after model is loaded' do
|
|
305
|
-
proc = Proc.new {
|
|
305
|
+
proc = Proc.new {}
|
|
306
306
|
|
|
307
307
|
expect(proc).to receive(:call) do |user|
|
|
308
308
|
expect(user).to eql @user.__getobj__
|
|
@@ -314,8 +314,8 @@ describe Acfs::Model::QueryMethods do
|
|
|
314
314
|
end
|
|
315
315
|
|
|
316
316
|
it 'should invoke multiple callbacks after model is loaded' do
|
|
317
|
-
proc1 = Proc.new {
|
|
318
|
-
proc2 = Proc.new {
|
|
317
|
+
proc1 = Proc.new {}
|
|
318
|
+
proc2 = Proc.new {}
|
|
319
319
|
|
|
320
320
|
expect(proc1).to receive(:call) do |user|
|
|
321
321
|
expect(user).to eql @user.__getobj__
|
|
@@ -339,7 +339,7 @@ describe Acfs::Model::QueryMethods do
|
|
|
339
339
|
it_behaves_like 'find_by'
|
|
340
340
|
|
|
341
341
|
context 'standard resource' do
|
|
342
|
-
let(:model){ MyUser }
|
|
342
|
+
let(:model) { MyUser }
|
|
343
343
|
let!(:user) { model.send described_method, age: 24 }
|
|
344
344
|
subject { Acfs.run; user }
|
|
345
345
|
|
|
@@ -348,16 +348,16 @@ describe Acfs::Model::QueryMethods do
|
|
|
348
348
|
|
|
349
349
|
it 'should raise an ResourceNotFound error' do
|
|
350
350
|
model.find_by! age: 24
|
|
351
|
-
expect{ Acfs.run }.to raise_error Acfs::ResourceNotFound
|
|
351
|
+
expect { Acfs.run }.to raise_error Acfs::ResourceNotFound
|
|
352
352
|
end
|
|
353
353
|
|
|
354
354
|
it 'should not invoke callback after model could not be loaded' do
|
|
355
|
-
proc = Proc.new {
|
|
355
|
+
proc = Proc.new {}
|
|
356
356
|
|
|
357
357
|
expect(proc).not_to receive(:call)
|
|
358
358
|
|
|
359
359
|
model.find_by! age: 24, &proc
|
|
360
|
-
expect{ Acfs.run }.to raise_error
|
|
360
|
+
expect { Acfs.run }.to raise_error
|
|
361
361
|
end
|
|
362
362
|
end
|
|
363
363
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: acfs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.34.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jan Graichen
|
|
@@ -14,98 +14,98 @@ dependencies:
|
|
|
14
14
|
name: activesupport
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- -
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '3.1'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- -
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '3.1'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: activemodel
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- -
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: '3.1'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- -
|
|
38
|
+
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '3.1'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: actionpack
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- -
|
|
45
|
+
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '3.1'
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- -
|
|
52
|
+
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '3.1'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: multi_json
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- -
|
|
59
|
+
- - ">="
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
61
|
version: '0'
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- -
|
|
66
|
+
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: typhoeus
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
|
-
- -
|
|
73
|
+
- - ">="
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
75
|
version: 0.6.5
|
|
76
76
|
type: :runtime
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
|
-
- -
|
|
80
|
+
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: 0.6.5
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: rack
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- -
|
|
87
|
+
- - ">="
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
89
|
version: '0'
|
|
90
90
|
type: :runtime
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
|
-
- -
|
|
94
|
+
- - ">="
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '0'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
98
|
name: bundler
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
|
-
- - ~>
|
|
101
|
+
- - "~>"
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
103
|
version: '1.3'
|
|
104
104
|
type: :development
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
|
-
- - ~>
|
|
108
|
+
- - "~>"
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '1.3'
|
|
111
111
|
description: API Client For Services
|
|
@@ -119,6 +119,7 @@ files:
|
|
|
119
119
|
- LICENSE
|
|
120
120
|
- README.md
|
|
121
121
|
- acfs.gemspec
|
|
122
|
+
- doc/file.README.html
|
|
122
123
|
- lib/acfs.rb
|
|
123
124
|
- lib/acfs/adapter/base.rb
|
|
124
125
|
- lib/acfs/adapter/typhoeus.rb
|
|
@@ -156,6 +157,7 @@ files:
|
|
|
156
157
|
- lib/acfs/model/service.rb
|
|
157
158
|
- lib/acfs/model/validation.rb
|
|
158
159
|
- lib/acfs/operation.rb
|
|
160
|
+
- lib/acfs/parameter_decoder.rb
|
|
159
161
|
- lib/acfs/request.rb
|
|
160
162
|
- lib/acfs/request/callbacks.rb
|
|
161
163
|
- lib/acfs/resource.rb
|
|
@@ -212,14 +214,14 @@ require_paths:
|
|
|
212
214
|
- lib
|
|
213
215
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
214
216
|
requirements:
|
|
215
|
-
- -
|
|
217
|
+
- - ">="
|
|
216
218
|
- !ruby/object:Gem::Version
|
|
217
219
|
version: '0'
|
|
218
220
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
221
|
requirements:
|
|
220
|
-
- -
|
|
222
|
+
- - ">="
|
|
221
223
|
- !ruby/object:Gem::Version
|
|
222
|
-
version:
|
|
224
|
+
version: '0'
|
|
223
225
|
requirements: []
|
|
224
226
|
rubyforge_project:
|
|
225
227
|
rubygems_version: 2.2.2
|
|
@@ -258,3 +260,4 @@ test_files:
|
|
|
258
260
|
- spec/support/response.rb
|
|
259
261
|
- spec/support/service.rb
|
|
260
262
|
- spec/support/shared/find_callbacks.rb
|
|
263
|
+
has_rdoc:
|