her 0.5.5 → 0.6
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 +8 -8
- data/.gitignore +1 -1
- data/README.md +78 -63
- data/UPGRADE.md +21 -0
- data/lib/her/model.rb +2 -1
- data/lib/her/model/associations.rb +17 -54
- data/lib/her/model/associations/association.rb +46 -0
- data/lib/her/model/associations/belongs_to_association.rb +34 -0
- data/lib/her/model/associations/has_many_association.rb +43 -0
- data/lib/her/model/associations/has_one_association.rb +33 -0
- data/lib/her/model/attributes.rb +19 -19
- data/lib/her/model/base.rb +5 -0
- data/lib/her/model/http.rb +17 -21
- data/lib/her/model/orm.rb +11 -35
- data/lib/her/model/parse.rb +4 -12
- data/lib/her/model/paths.rb +3 -2
- data/lib/her/model/relation.rb +113 -0
- data/lib/her/version.rb +1 -1
- data/spec/model/associations_spec.rb +48 -4
- data/spec/model/introspection_spec.rb +1 -1
- data/spec/model/orm_spec.rb +21 -102
- data/spec/model/parse_spec.rb +36 -7
- data/spec/model/paths_spec.rb +3 -3
- data/spec/model/relation_spec.rb +89 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/macros/her_macros.rb +17 -0
- data/spec/support/macros/request_macros.rb +19 -0
- metadata +13 -37
- data/examples/grape-and-her/.env.default +0 -3
- data/examples/grape-and-her/Procfile +0 -2
- data/examples/grape-and-her/README.md +0 -27
- data/examples/grape-and-her/api/Gemfile +0 -11
- data/examples/grape-and-her/api/Rakefile +0 -14
- data/examples/grape-and-her/api/app/api.rb +0 -49
- data/examples/grape-and-her/api/app/models/organization.rb +0 -7
- data/examples/grape-and-her/api/app/models/user.rb +0 -9
- data/examples/grape-and-her/api/app/views/organizations/_base.rabl +0 -2
- data/examples/grape-and-her/api/app/views/organizations/index.rabl +0 -3
- data/examples/grape-and-her/api/app/views/organizations/show.rabl +0 -3
- data/examples/grape-and-her/api/app/views/users/_base.rabl +0 -8
- data/examples/grape-and-her/api/app/views/users/index.rabl +0 -3
- data/examples/grape-and-her/api/app/views/users/show.rabl +0 -3
- data/examples/grape-and-her/api/config.ru +0 -5
- data/examples/grape-and-her/api/config/boot.rb +0 -17
- data/examples/grape-and-her/api/config/unicorn.rb +0 -7
- data/examples/grape-and-her/api/db/migrations/001_create_users.rb +0 -11
- data/examples/grape-and-her/api/db/migrations/002_create_organizations.rb +0 -8
- data/examples/grape-and-her/consumer/Gemfile +0 -23
- data/examples/grape-and-her/consumer/app/assets/stylesheets/application.scss +0 -190
- data/examples/grape-and-her/consumer/app/assets/stylesheets/reset.scss +0 -53
- data/examples/grape-and-her/consumer/app/consumer.rb +0 -74
- data/examples/grape-and-her/consumer/app/models/organization.rb +0 -13
- data/examples/grape-and-her/consumer/app/models/user.rb +0 -13
- data/examples/grape-and-her/consumer/app/views/index.haml +0 -9
- data/examples/grape-and-her/consumer/app/views/layout.haml +0 -20
- data/examples/grape-and-her/consumer/app/views/organizations/index.haml +0 -25
- data/examples/grape-and-her/consumer/app/views/organizations/show.haml +0 -11
- data/examples/grape-and-her/consumer/app/views/users/index.haml +0 -33
- data/examples/grape-and-her/consumer/app/views/users/show.haml +0 -9
- data/examples/grape-and-her/consumer/config.ru +0 -20
- data/examples/grape-and-her/consumer/config/boot.rb +0 -30
- data/examples/grape-and-her/consumer/config/unicorn.rb +0 -7
- data/examples/grape-and-her/consumer/lib/response_logger.rb +0 -18
data/spec/model/paths_spec.rb
CHANGED
@@ -194,7 +194,7 @@ describe Her::Model::Paths do
|
|
194
194
|
|
195
195
|
describe "fetching a collection" do
|
196
196
|
it "maps a collection of resources to an array of Ruby objects" do
|
197
|
-
@users = Foo::User.
|
197
|
+
@users = Foo::User.where(:_organization_id => 2).all
|
198
198
|
@users.length.should == 2
|
199
199
|
@users.first.fullname.should == "Tobias Fünke"
|
200
200
|
end
|
@@ -285,7 +285,7 @@ describe Her::Model::Paths do
|
|
285
285
|
|
286
286
|
describe "fetching a collection" do
|
287
287
|
it "maps a collection of resources to an array of Ruby objects" do
|
288
|
-
@users = Foo::User.
|
288
|
+
@users = Foo::User.where(:_organization_id => 2).all
|
289
289
|
@users.length.should == 2
|
290
290
|
@users.first.fullname.should == "Tobias Fünke"
|
291
291
|
end
|
@@ -303,7 +303,7 @@ describe Her::Model::Paths do
|
|
303
303
|
describe "fetching a collection with absolute path" do
|
304
304
|
it "maps a collection of resources to an array of Ruby objects" do
|
305
305
|
Foo::User.collection_path '/api/' + Foo::User.collection_path
|
306
|
-
@users = Foo::User.
|
306
|
+
@users = Foo::User.where(:_organization_id => 2).all
|
307
307
|
@users.length.should == 2
|
308
308
|
@users.first.fullname.should == "Tobias Fünke"
|
309
309
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.join(File.dirname(__FILE__), "../spec_helper.rb")
|
3
|
+
|
4
|
+
describe Her::Model::Relation do
|
5
|
+
describe :where do
|
6
|
+
before do
|
7
|
+
Her::API.setup :url => "https://api.example.com" do |builder|
|
8
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
9
|
+
builder.adapter :test do |stub|
|
10
|
+
stub.get("/users") { |env| ok! [{ :id => 1, :fullname => "Tobias Fünke" }, { :id => 2, :fullname => "Lindsay Fünke" }] }
|
11
|
+
stub.get("/users?admin=1") { |env| ok! [{ :id => 1, :fullname => "Tobias Fünke" }] }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
spawn_model "Foo::User"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "doesn't fetch the data immediatly" do
|
19
|
+
Her::Model::Relation.any_instance.should_receive(:fetch).never
|
20
|
+
@users = Foo::User.where(:admin => 1)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "fetches the data and passes query parameters" do
|
24
|
+
Her::Model::Relation.any_instance.should_receive(:fetch).once.and_call_original
|
25
|
+
@users = Foo::User.where(:admin => 1)
|
26
|
+
@users.length.should == 2
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe :create do
|
31
|
+
before do
|
32
|
+
Her::API.setup :url => "https://api.example.com" do |builder|
|
33
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
34
|
+
builder.use Faraday::Request::UrlEncoded
|
35
|
+
builder.adapter :test do |stub|
|
36
|
+
stub.post("/users") { |env| ok! :id => 1, :fullname => params(env)[:fullname], :email => params(env)[:email] }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
spawn_model "Foo::User"
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with a single where call" do
|
44
|
+
it "creates a resource and passes the query parameters" do
|
45
|
+
@user = Foo::User.where(:fullname => "Tobias Fünke", :email => "tobias@bluth.com").create
|
46
|
+
@user.id.should == 1
|
47
|
+
@user.fullname.should == "Tobias Fünke"
|
48
|
+
@user.email.should == "tobias@bluth.com"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "with multiple where calls" do
|
53
|
+
it "creates a resource and passes the query parameters" do
|
54
|
+
@user = Foo::User.where(:fullname => "Tobias Fünke").create(:email => "tobias@bluth.com")
|
55
|
+
@user.id.should == 1
|
56
|
+
@user.fullname.should == "Tobias Fünke"
|
57
|
+
@user.email.should == "tobias@bluth.com"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#page and #per_page" do
|
63
|
+
before do
|
64
|
+
Her::API.setup :url => "https://api.example.com" do |builder|
|
65
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
66
|
+
builder.adapter :test do |stub|
|
67
|
+
stub.get("/users?page=2&per_page=1") { |env| ok! [{ :id => 2, :fullname => "Lindsay Fünke" }] }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
spawn_model "Foo::User"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "passes the pagination parameters" do
|
75
|
+
@user = Foo::User.page(2).per_page(1).first
|
76
|
+
@user.id.should == 2
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe :build do
|
81
|
+
before { spawn_model "Foo::User" }
|
82
|
+
|
83
|
+
it "handles new resource with build" do
|
84
|
+
@new_user = Foo::User.where(:fullname => "Tobias Fünke").build
|
85
|
+
@new_user.new?.should be_true
|
86
|
+
@new_user.fullname.should == "Tobias Fünke"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -8,6 +8,7 @@ Dir[File.expand_path('../../spec/support/**/*.rb', __FILE__)].map(&method(:requi
|
|
8
8
|
|
9
9
|
RSpec.configure do |config|
|
10
10
|
config.include Her::Testing::Macros::ModelMacros
|
11
|
+
config.include Her::Testing::Macros::RequestMacros
|
11
12
|
|
12
13
|
config.before :each do
|
13
14
|
@spawned_models = []
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Her
|
2
|
+
module Testing
|
3
|
+
module Macros
|
4
|
+
module RequestMacros
|
5
|
+
def ok!(body)
|
6
|
+
[200, {}, body.to_json]
|
7
|
+
end
|
8
|
+
|
9
|
+
def error!(body)
|
10
|
+
[400, {}, body.to_json]
|
11
|
+
end
|
12
|
+
|
13
|
+
def params(env)
|
14
|
+
@params ||= Faraday::Utils.parse_query(env[:body]).with_indifferent_access
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: her
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rémi Prévost
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-04-
|
11
|
+
date: 2013-04-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -124,41 +124,6 @@ files:
|
|
124
124
|
- README.md
|
125
125
|
- Rakefile
|
126
126
|
- UPGRADE.md
|
127
|
-
- examples/grape-and-her/.env.default
|
128
|
-
- examples/grape-and-her/Procfile
|
129
|
-
- examples/grape-and-her/README.md
|
130
|
-
- examples/grape-and-her/api/Gemfile
|
131
|
-
- examples/grape-and-her/api/Rakefile
|
132
|
-
- examples/grape-and-her/api/app/api.rb
|
133
|
-
- examples/grape-and-her/api/app/models/organization.rb
|
134
|
-
- examples/grape-and-her/api/app/models/user.rb
|
135
|
-
- examples/grape-and-her/api/app/views/organizations/_base.rabl
|
136
|
-
- examples/grape-and-her/api/app/views/organizations/index.rabl
|
137
|
-
- examples/grape-and-her/api/app/views/organizations/show.rabl
|
138
|
-
- examples/grape-and-her/api/app/views/users/_base.rabl
|
139
|
-
- examples/grape-and-her/api/app/views/users/index.rabl
|
140
|
-
- examples/grape-and-her/api/app/views/users/show.rabl
|
141
|
-
- examples/grape-and-her/api/config.ru
|
142
|
-
- examples/grape-and-her/api/config/boot.rb
|
143
|
-
- examples/grape-and-her/api/config/unicorn.rb
|
144
|
-
- examples/grape-and-her/api/db/migrations/001_create_users.rb
|
145
|
-
- examples/grape-and-her/api/db/migrations/002_create_organizations.rb
|
146
|
-
- examples/grape-and-her/consumer/Gemfile
|
147
|
-
- examples/grape-and-her/consumer/app/assets/stylesheets/application.scss
|
148
|
-
- examples/grape-and-her/consumer/app/assets/stylesheets/reset.scss
|
149
|
-
- examples/grape-and-her/consumer/app/consumer.rb
|
150
|
-
- examples/grape-and-her/consumer/app/models/organization.rb
|
151
|
-
- examples/grape-and-her/consumer/app/models/user.rb
|
152
|
-
- examples/grape-and-her/consumer/app/views/index.haml
|
153
|
-
- examples/grape-and-her/consumer/app/views/layout.haml
|
154
|
-
- examples/grape-and-her/consumer/app/views/organizations/index.haml
|
155
|
-
- examples/grape-and-her/consumer/app/views/organizations/show.haml
|
156
|
-
- examples/grape-and-her/consumer/app/views/users/index.haml
|
157
|
-
- examples/grape-and-her/consumer/app/views/users/show.haml
|
158
|
-
- examples/grape-and-her/consumer/config.ru
|
159
|
-
- examples/grape-and-her/consumer/config/boot.rb
|
160
|
-
- examples/grape-and-her/consumer/config/unicorn.rb
|
161
|
-
- examples/grape-and-her/consumer/lib/response_logger.rb
|
162
127
|
- her.gemspec
|
163
128
|
- lib/her.rb
|
164
129
|
- lib/her/api.rb
|
@@ -171,6 +136,10 @@ files:
|
|
171
136
|
- lib/her/middleware/second_level_parse_json.rb
|
172
137
|
- lib/her/model.rb
|
173
138
|
- lib/her/model/associations.rb
|
139
|
+
- lib/her/model/associations/association.rb
|
140
|
+
- lib/her/model/associations/belongs_to_association.rb
|
141
|
+
- lib/her/model/associations/has_many_association.rb
|
142
|
+
- lib/her/model/associations/has_one_association.rb
|
174
143
|
- lib/her/model/attributes.rb
|
175
144
|
- lib/her/model/base.rb
|
176
145
|
- lib/her/model/http.rb
|
@@ -179,6 +148,7 @@ files:
|
|
179
148
|
- lib/her/model/orm.rb
|
180
149
|
- lib/her/model/parse.rb
|
181
150
|
- lib/her/model/paths.rb
|
151
|
+
- lib/her/model/relation.rb
|
182
152
|
- lib/her/version.rb
|
183
153
|
- spec/api_spec.rb
|
184
154
|
- spec/collection_spec.rb
|
@@ -195,12 +165,15 @@ files:
|
|
195
165
|
- spec/model/orm_spec.rb
|
196
166
|
- spec/model/parse_spec.rb
|
197
167
|
- spec/model/paths_spec.rb
|
168
|
+
- spec/model/relation_spec.rb
|
198
169
|
- spec/model/validations_spec.rb
|
199
170
|
- spec/model_spec.rb
|
200
171
|
- spec/spec_helper.rb
|
201
172
|
- spec/support/extensions/array.rb
|
202
173
|
- spec/support/extensions/hash.rb
|
174
|
+
- spec/support/macros/her_macros.rb
|
203
175
|
- spec/support/macros/model_macros.rb
|
176
|
+
- spec/support/macros/request_macros.rb
|
204
177
|
homepage: http://remiprev.github.com/her
|
205
178
|
licenses:
|
206
179
|
- MIT
|
@@ -242,9 +215,12 @@ test_files:
|
|
242
215
|
- spec/model/orm_spec.rb
|
243
216
|
- spec/model/parse_spec.rb
|
244
217
|
- spec/model/paths_spec.rb
|
218
|
+
- spec/model/relation_spec.rb
|
245
219
|
- spec/model/validations_spec.rb
|
246
220
|
- spec/model_spec.rb
|
247
221
|
- spec/spec_helper.rb
|
248
222
|
- spec/support/extensions/array.rb
|
249
223
|
- spec/support/extensions/hash.rb
|
224
|
+
- spec/support/macros/her_macros.rb
|
250
225
|
- spec/support/macros/model_macros.rb
|
226
|
+
- spec/support/macros/request_macros.rb
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# Grape + Her example
|
2
|
-
|
3
|
-
This is an example of how to use Her to consume a simple API. It consists of two separate applications, a REST API (powered by `grape` and `activerecord`) and a consumer application (powered by `sinatra` and `her`).
|
4
|
-
|
5
|
-

|
6
|
-
|
7
|
-
## Installation and Usage
|
8
|
-
|
9
|
-
```shell
|
10
|
-
# Clone the repository
|
11
|
-
$ git clone git://github.com/remiprev/her.git
|
12
|
-
|
13
|
-
# Go to the example directory
|
14
|
-
$ cd her/examples/grape-and-her
|
15
|
-
|
16
|
-
# Go to each application and run `bundle install`
|
17
|
-
$ cd api; bundle install; cd ..
|
18
|
-
$ cd consumer; bundle install; cd ..
|
19
|
-
|
20
|
-
# Create the API database
|
21
|
-
$ cd api; sqlite3 db/development.db ""; bundle exec rake db:migrate; cd ..
|
22
|
-
|
23
|
-
# Start foreman with the Procfile
|
24
|
-
$ foreman start
|
25
|
-
```
|
26
|
-
|
27
|
-
This should start the API on `http://0.0.0.0:3100` and the consumer on `http://0.0.0.0:3200`
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'portugal/tasks'
|
2
|
-
Portugal.configure do |config|
|
3
|
-
config.migrations_path = File.expand_path("../db/migrations", __FILE__)
|
4
|
-
end
|
5
|
-
|
6
|
-
# This task is called before Portugal executes its tasks.
|
7
|
-
# It should require ActiveRecord somehow and establish the database connection
|
8
|
-
#
|
9
|
-
# Change it so it works for your application
|
10
|
-
task :environment do
|
11
|
-
require 'bundler'
|
12
|
-
Bundler.require
|
13
|
-
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: File.expand_path('../db/development.db', __FILE__)
|
14
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
class API < Grape::API
|
2
|
-
content_type :json, "application/json; charset=UTF-8"
|
3
|
-
format :json
|
4
|
-
formatter :json, Grape::Formatter::Rabl
|
5
|
-
use(Rack::Config) { |env| env['api.tilt.root'] = File.expand_path('../views', __FILE__) }
|
6
|
-
rescue_from :all
|
7
|
-
|
8
|
-
resources :users do
|
9
|
-
desc 'Return all users'
|
10
|
-
get nil, :rabl => "users/index" do
|
11
|
-
@users = User.all
|
12
|
-
end
|
13
|
-
|
14
|
-
desc 'Return a specific user'
|
15
|
-
get ':id', :rabl => "users/show" do
|
16
|
-
@user = User.find(params[:id])
|
17
|
-
end
|
18
|
-
|
19
|
-
desc 'Create a new user'
|
20
|
-
post nil, :rabl => "users/show" do
|
21
|
-
@user = User.new(params[:user])
|
22
|
-
error!({ :errors => @user.errors.full_messages }, 400) unless @user.save
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
resources :organizations do
|
27
|
-
desc 'Return all organizations'
|
28
|
-
get nil, :rabl => "organizations/index" do
|
29
|
-
@organizations = Organization.all
|
30
|
-
end
|
31
|
-
|
32
|
-
desc 'Return a specific organization'
|
33
|
-
get ':id', :rabl => "organizations/show" do
|
34
|
-
@organization = Organization.find(params[:id])
|
35
|
-
end
|
36
|
-
|
37
|
-
desc 'Return all users for specific organization'
|
38
|
-
get ':id/users', :rabl => "users/index" do
|
39
|
-
organization = Organization.find(params[:id])
|
40
|
-
@users = organization.users
|
41
|
-
end
|
42
|
-
|
43
|
-
desc 'Create a new organization'
|
44
|
-
post nil, :rabl => "organizations/show" do
|
45
|
-
@organization = Organization.new(params[:organization])
|
46
|
-
error!({ :errors => @organization.errors.full_messages }, 400) unless @organization.save
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|