her 0.5.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +1 -1
  3. data/README.md +78 -63
  4. data/UPGRADE.md +21 -0
  5. data/lib/her/model.rb +2 -1
  6. data/lib/her/model/associations.rb +17 -54
  7. data/lib/her/model/associations/association.rb +46 -0
  8. data/lib/her/model/associations/belongs_to_association.rb +34 -0
  9. data/lib/her/model/associations/has_many_association.rb +43 -0
  10. data/lib/her/model/associations/has_one_association.rb +33 -0
  11. data/lib/her/model/attributes.rb +19 -19
  12. data/lib/her/model/base.rb +5 -0
  13. data/lib/her/model/http.rb +17 -21
  14. data/lib/her/model/orm.rb +11 -35
  15. data/lib/her/model/parse.rb +4 -12
  16. data/lib/her/model/paths.rb +3 -2
  17. data/lib/her/model/relation.rb +113 -0
  18. data/lib/her/version.rb +1 -1
  19. data/spec/model/associations_spec.rb +48 -4
  20. data/spec/model/introspection_spec.rb +1 -1
  21. data/spec/model/orm_spec.rb +21 -102
  22. data/spec/model/parse_spec.rb +36 -7
  23. data/spec/model/paths_spec.rb +3 -3
  24. data/spec/model/relation_spec.rb +89 -0
  25. data/spec/spec_helper.rb +1 -0
  26. data/spec/support/macros/her_macros.rb +17 -0
  27. data/spec/support/macros/request_macros.rb +19 -0
  28. metadata +13 -37
  29. data/examples/grape-and-her/.env.default +0 -3
  30. data/examples/grape-and-her/Procfile +0 -2
  31. data/examples/grape-and-her/README.md +0 -27
  32. data/examples/grape-and-her/api/Gemfile +0 -11
  33. data/examples/grape-and-her/api/Rakefile +0 -14
  34. data/examples/grape-and-her/api/app/api.rb +0 -49
  35. data/examples/grape-and-her/api/app/models/organization.rb +0 -7
  36. data/examples/grape-and-her/api/app/models/user.rb +0 -9
  37. data/examples/grape-and-her/api/app/views/organizations/_base.rabl +0 -2
  38. data/examples/grape-and-her/api/app/views/organizations/index.rabl +0 -3
  39. data/examples/grape-and-her/api/app/views/organizations/show.rabl +0 -3
  40. data/examples/grape-and-her/api/app/views/users/_base.rabl +0 -8
  41. data/examples/grape-and-her/api/app/views/users/index.rabl +0 -3
  42. data/examples/grape-and-her/api/app/views/users/show.rabl +0 -3
  43. data/examples/grape-and-her/api/config.ru +0 -5
  44. data/examples/grape-and-her/api/config/boot.rb +0 -17
  45. data/examples/grape-and-her/api/config/unicorn.rb +0 -7
  46. data/examples/grape-and-her/api/db/migrations/001_create_users.rb +0 -11
  47. data/examples/grape-and-her/api/db/migrations/002_create_organizations.rb +0 -8
  48. data/examples/grape-and-her/consumer/Gemfile +0 -23
  49. data/examples/grape-and-her/consumer/app/assets/stylesheets/application.scss +0 -190
  50. data/examples/grape-and-her/consumer/app/assets/stylesheets/reset.scss +0 -53
  51. data/examples/grape-and-her/consumer/app/consumer.rb +0 -74
  52. data/examples/grape-and-her/consumer/app/models/organization.rb +0 -13
  53. data/examples/grape-and-her/consumer/app/models/user.rb +0 -13
  54. data/examples/grape-and-her/consumer/app/views/index.haml +0 -9
  55. data/examples/grape-and-her/consumer/app/views/layout.haml +0 -20
  56. data/examples/grape-and-her/consumer/app/views/organizations/index.haml +0 -25
  57. data/examples/grape-and-her/consumer/app/views/organizations/show.haml +0 -11
  58. data/examples/grape-and-her/consumer/app/views/users/index.haml +0 -33
  59. data/examples/grape-and-her/consumer/app/views/users/show.haml +0 -9
  60. data/examples/grape-and-her/consumer/config.ru +0 -20
  61. data/examples/grape-and-her/consumer/config/boot.rb +0 -30
  62. data/examples/grape-and-her/consumer/config/unicorn.rb +0 -7
  63. data/examples/grape-and-her/consumer/lib/response_logger.rb +0 -18
@@ -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.all(:_organization_id => 2)
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.all(:_organization_id => 2)
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.all(:_organization_id => 2)
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,17 @@
1
+ module Her
2
+ module Testing
3
+ module Macros
4
+ def ok!(body)
5
+ [200, {}, body.to_json]
6
+ end
7
+
8
+ def error!(body)
9
+ [400, {}, body.to_json]
10
+ end
11
+
12
+ def params(env)
13
+ Faraday::Utils.parse_query(env[:body])
14
+ end
15
+ end
16
+ end
17
+ end
@@ -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.5.5
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-18 00:00:00.000000000 Z
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,3 +0,0 @@
1
- RACK_ENV=development
2
- API_PORT=3100
3
- CONSUMER_PORT=3200
@@ -1,2 +0,0 @@
1
- api: ruby -C ./api -S bundle exec unicorn -p $API_PORT -c ./config/unicorn.rb -E $RACK_ENV
2
- consumer: ruby -C ./consumer -S bundle exec unicorn -p $CONSUMER_PORT -c ./config/unicorn.rb -E $RACK_ENV
@@ -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
- ![](http://i.imgur.com/AGfYwzl.png)
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,11 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Server
4
- gem 'unicorn'
5
-
6
- # App
7
- gem 'grape'
8
- gem 'sqlite3'
9
- gem 'activerecord', '~> 3.2'
10
- gem 'portugal'
11
- gem 'grape-rabl'
@@ -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
@@ -1,7 +0,0 @@
1
- class Organization < ActiveRecord::Base
2
- # Associations
3
- has_many :users
4
-
5
- # Validations
6
- validates :name, presence: true
7
- end
@@ -1,9 +0,0 @@
1
- class User < ActiveRecord::Base
2
- # Associations
3
- belongs_to :organization
4
-
5
- # Validations
6
- validates :email, presence: true
7
- validates :fullname, presence: true
8
- validates :organization, presence: true
9
- end
@@ -1,2 +0,0 @@
1
- attribute :id
2
- attribute :name
@@ -1,3 +0,0 @@
1
- collection @organizations
2
-
3
- extends("organizations/base")
@@ -1,3 +0,0 @@
1
- object @organization
2
-
3
- extends("organizations/base")
@@ -1,8 +0,0 @@
1
- attribute :id
2
- attribute :email
3
- attribute :fullname
4
- attribute :organization_id
5
-
6
- child :organization do
7
- extends("organizations/base")
8
- end
@@ -1,3 +0,0 @@
1
- collection @users
2
-
3
- extends("users/base")
@@ -1,3 +0,0 @@
1
- object @user
2
-
3
- extends("users/base")
@@ -1,5 +0,0 @@
1
- require File.expand_path('../config/boot', __FILE__)
2
-
3
- map "/" do
4
- run API
5
- end