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.
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