restaurant 0.0.1 → 0.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7fb21aa890ec7f4772dc2e12122ec1cc13ea5708
4
+ data.tar.gz: 71c730838eb22204bfc1f2118d742789daf5c76c
5
+ SHA512:
6
+ metadata.gz: 46a16736907c671d72bff370cdb9ac952a47b56fcde3bfc05f53eb76d0af9aca20f37026fbf902806a9f3b2a9a7559de3c4cea280f67f54a9d2b64cb7a69ad18
7
+ data.tar.gz: 8bf6d5ab874825e3af1c160845bc3949e8ef5b102b167729ea49ef87fac96e77e732db82604e7157f5c8f3c2f4b95d41a6d571964894b6f690face7e46dc3392
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2013 YOURNAME
1
+ Copyright 2013 Ryo Nakamura
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,2 +1,86 @@
1
1
  # Restaurant
2
2
  Restaurant serves RESTful API on Rails.
3
+
4
+ ## Features
5
+
6
+ ### No more controllers, No more routes
7
+ Restaurant provides strict RESTful API implementation for your models.
8
+ All controllers and routings will be auto-defined based on your config/restaurant.yml definition.
9
+ No need to write any more app/controllers and config/routes.rb.
10
+ All you have to do is write your models and authorization yaml file.
11
+
12
+ ```ruby
13
+ # app/controllers/application_controller.rb
14
+ class ApplicationController < ActionController::Base
15
+ include Restaurant::ControllerHelper
16
+ end
17
+ ```
18
+
19
+ ```ruby
20
+ # config/routes.rb
21
+ Rails.application.routes.draw do
22
+ Restaurant::Router.route(self)
23
+ end
24
+ ```
25
+
26
+ ```yaml
27
+ # config/restaurant.yml
28
+ public:
29
+ recipes:
30
+ actions:
31
+ - index
32
+ - show
33
+ users:
34
+ actions:
35
+ - show
36
+ ```
37
+
38
+ ### Authorization
39
+ You can restrict users by their scopes, accessed actions, and used queries.
40
+
41
+ * User with "public" scope token
42
+ * can access /recipes/:id
43
+ * User with "admin" scope token
44
+ * can access /recipes/:id
45
+ * can access /recipes
46
+ * can filter recipes by id and title
47
+ * can sort recipes by id and title
48
+
49
+ ```yaml
50
+ # config/restaurant.yml
51
+ public:
52
+ recipes:
53
+ actions:
54
+ - show
55
+ admin:
56
+ recipes:
57
+ actions:
58
+ - index
59
+ - show
60
+ where:
61
+ - id
62
+ - title
63
+ order:
64
+ - id
65
+ - title
66
+ ```
67
+
68
+ ### SQL-like URI query
69
+ Our restraunt serves SQL-like URI query system.
70
+
71
+ ```ruby
72
+ context "with where params" do
73
+ it "returns recipes filtered by given query" do
74
+ get "/recipes", { where: { title: { eq: recipe.title } } }, env
75
+ response.should be_ok
76
+ response.body.should be_json(
77
+ "id" => 1,
78
+ "user_id" => 1
79
+ "body" => "body 1",
80
+ "title" => "title 1",
81
+ "updated_at" => "2000-01-01T00:00:00Z",
82
+ "created_at" => "2000-01-01T00:00:00Z",
83
+ )
84
+ end
85
+ end
86
+ ```
data/lib/restaurant.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "restaurant/engine"
2
- require "restaurant/accept_default"
1
+ require "restaurant/authentication"
2
+ require "restaurant/authorization"
3
3
  require "restaurant/config"
4
4
  require "restaurant/controller_helper"
5
5
  require "restaurant/controller_provider"
@@ -8,6 +8,7 @@ require "restaurant/params_query_responder"
8
8
  require "restaurant/params_query_translator"
9
9
  require "restaurant/restful_actions"
10
10
  require "restaurant/router"
11
+ require "restaurant/railtie"
11
12
 
12
13
  module Restaurant
13
14
  end
@@ -0,0 +1,7 @@
1
+ module Restaurant::Authentication
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ doorkeeper_for :all
6
+ end
7
+ end
@@ -0,0 +1,85 @@
1
+ module Restaurant::Authorization
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_filter :require_authorization
6
+ end
7
+
8
+ private
9
+
10
+ def require_authorization
11
+ head 403 unless has_authorization?
12
+ end
13
+
14
+ def has_authorization?
15
+ has_action_authorization? && has_query_authorization?
16
+ end
17
+
18
+ def has_action_authorization?
19
+ controllers_set.any? do |controllers|
20
+ if controller = controllers[controller_name]
21
+ controller["actions"].include?(action_name)
22
+ end
23
+ end
24
+ end
25
+
26
+ def has_query_authorization?
27
+ if has_not_allowed_where? || has_not_allowed_order?
28
+ false
29
+ else
30
+ true
31
+ end
32
+ end
33
+
34
+ def controllers_set
35
+ @controllers_set ||= Restaurant::Config.roles.inject([]) do |result, (role, controllers)|
36
+ result << controllers if doorkeeper_token.scopes.include?(role.to_sym)
37
+ result
38
+ end
39
+ end
40
+
41
+ def has_where_query?
42
+ params[:where]
43
+ end
44
+
45
+ def has_order_query?
46
+ params[:order]
47
+ end
48
+
49
+ def current_abilities
50
+ @current_abilities ||= controllers_set.inject([]) do |abilities, controllers|
51
+ abilities << controllers[controller_name] if controllers[controller_name]
52
+ abilities
53
+ end
54
+ end
55
+
56
+ def current_order_abilities
57
+ current_abilities.inject([]) do |columns, ability|
58
+ columns + (ability["order"] || [])
59
+ end
60
+ end
61
+
62
+ def current_where_abilities
63
+ current_abilities.inject([]) do |columns, ability|
64
+ columns + (ability["where"] || [])
65
+ end
66
+ end
67
+
68
+ def has_not_allowed_where?
69
+ has_where_query? && (where_queries - current_where_abilities).any?
70
+ end
71
+
72
+ def has_not_allowed_order?
73
+ has_order_query? && (order_queries - current_order_abilities).any?
74
+ end
75
+
76
+ def where_queries
77
+ params[:where].keys
78
+ end
79
+
80
+ def order_queries
81
+ Array.wrap(params[:order]).map do |column|
82
+ column.sub(/^-/, "")
83
+ end
84
+ end
85
+ end
@@ -11,7 +11,7 @@ module Restaurant::Config
11
11
  end
12
12
 
13
13
  def path
14
- Rails.root.join("config/roles.yml").tap do |path|
14
+ Rails.root.join("config/restaurant.yml").tap do |path|
15
15
  raise NoRolesError, "#{path} is not found" unless path.exist?
16
16
  end
17
17
  end
@@ -2,10 +2,12 @@ module Restaurant::ControllerHelper
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- include Restaurant::AcceptDefault
5
+ use Rack::AcceptDefault
6
6
  include Restaurant::ControllerProvider
7
7
  include Restaurant::ModelClassFinder
8
8
  include Restaurant::RestfulActions
9
+ include Restaurant::Authentication
10
+ include Restaurant::Authorization
9
11
  self.responder = Restaurant::ParamsQueryResponder
10
12
  end
11
13
  end
@@ -35,7 +35,7 @@ class Restaurant::ParamsQueryTranslator
35
35
  end
36
36
 
37
37
  def where
38
- params[:where] || []
38
+ params[:where] || {}
39
39
  end
40
40
 
41
41
  def order
@@ -56,12 +56,8 @@ class Restaurant::ParamsQueryTranslator
56
56
  end
57
57
 
58
58
  def call(resources)
59
- if value.is_a? String
60
- self.class.new(key => { "eq" => value }).call(*args)
61
- else
62
- sections.inject(resources) do |relation, section|
63
- relation.where("#{column} #{section.operator}", *section.operand)
64
- end
59
+ sections.inject(resources) do |relation, section|
60
+ relation.where("#{column} #{section.operator}", *section.operand)
65
61
  end
66
62
  end
67
63
 
@@ -82,15 +78,36 @@ class Restaurant::ParamsQueryTranslator
82
78
  end
83
79
 
84
80
  def operator
85
- case raw_operator
86
- when "eq"
87
- "= ?"
81
+ if raw_operand.nil?
82
+ case raw_operator
83
+ when "eq"
84
+ "IS NULL"
85
+ when "ne"
86
+ "IS NOT NULL"
87
+ end
88
+ else
89
+ case raw_operator
90
+ when "eq"
91
+ "= ?"
92
+ when "ne"
93
+ "!= ?"
94
+ when "lt"
95
+ "< ?"
96
+ when "lte"
97
+ "<= ?"
98
+ when "gt"
99
+ "> ?"
100
+ when "gte"
101
+ ">= ?"
102
+ when "in"
103
+ "IN (?)"
104
+ end
88
105
  end
89
106
  end
90
107
 
91
108
  def operand
92
109
  case raw_operand
93
- when true
110
+ when nil
94
111
  []
95
112
  else
96
113
  [raw_operand]
@@ -100,32 +117,54 @@ class Restaurant::ParamsQueryTranslator
100
117
  end
101
118
 
102
119
  class OrderFilter
103
- attr_reader :raw_column
120
+ attr_reader :columns
104
121
 
105
- def initialize(raw_column)
106
- @raw_column = raw_column
122
+ def initialize(columns)
123
+ @columns = columns
107
124
  end
108
125
 
109
126
  def call(resources)
110
- resources.order("#{column} #{order}")
127
+ sections.inject(resources) do |result, section|
128
+ result.order(section.sort)
129
+ end
130
+ end
131
+
132
+ def sections
133
+ Array.wrap(columns).map do |column|
134
+ Section.new(column)
135
+ end
111
136
  end
112
137
 
113
138
  private
114
139
 
115
- def column
116
- raw_column.to_s.gsub(/^-/, "")
117
- end
140
+ class Section
141
+ attr_reader :raw_column
118
142
 
119
- def order
120
- if desc?
121
- "DESC"
122
- else
123
- "ASC"
143
+ def initialize(raw_column)
144
+ @raw_column = raw_column
124
145
  end
125
- end
126
146
 
127
- def desc?
128
- /^-/ === raw_column.to_s
147
+ def sort
148
+ "#{column} #{order}"
149
+ end
150
+
151
+ private
152
+
153
+ def column
154
+ raw_column.to_s.gsub(/^-/, "")
155
+ end
156
+
157
+ def order
158
+ if desc?
159
+ "DESC"
160
+ else
161
+ "ASC"
162
+ end
163
+ end
164
+
165
+ def desc?
166
+ /^-/ === raw_column.to_s
167
+ end
129
168
  end
130
169
  end
131
170
  end
@@ -0,0 +1,6 @@
1
+ # Force to load ApplicationController to define the other controllers.
2
+ class Restaurant::Railtie < Rails::Railtie
3
+ config.after_initialize do
4
+ ::ApplicationController
5
+ end
6
+ end
@@ -1,3 +1,3 @@
1
1
  module Restaurant
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restaurant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- prerelease:
4
+ version: 0.0.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ryo Nakamura
@@ -14,7 +13,6 @@ dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rails
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,81 +27,141 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rack-accept-default
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: doorkeeper
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.7
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.7
55
+ - !ruby/object:Gem::Dependency
56
+ name: jquery-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
44
67
  - !ruby/object:Gem::Version
45
68
  version: '0'
46
69
  - !ruby/object:Gem::Dependency
47
70
  name: sqlite3
48
71
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
72
  requirements:
51
- - - ! '>='
73
+ - - '>='
52
74
  - !ruby/object:Gem::Version
53
75
  version: '0'
54
76
  type: :development
55
77
  prerelease: false
56
78
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
79
  requirements:
59
- - - ! '>='
80
+ - - '>='
60
81
  - !ruby/object:Gem::Version
61
82
  version: '0'
62
83
  - !ruby/object:Gem::Dependency
63
84
  name: rspec-rails
64
85
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
86
  requirements:
67
- - - ! '>='
87
+ - - '>='
68
88
  - !ruby/object:Gem::Version
69
89
  version: 2.13.0
70
90
  type: :development
71
91
  prerelease: false
72
92
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
93
  requirements:
75
- - - ! '>='
94
+ - - '>='
76
95
  - !ruby/object:Gem::Version
77
96
  version: 2.13.0
78
97
  - !ruby/object:Gem::Dependency
79
98
  name: rspec-json_matcher
80
99
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
100
  requirements:
83
- - - ! '>='
101
+ - - '>='
84
102
  - !ruby/object:Gem::Version
85
103
  version: '0'
86
104
  type: :development
87
105
  prerelease: false
88
106
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
107
  requirements:
91
- - - ! '>='
108
+ - - '>='
92
109
  - !ruby/object:Gem::Version
93
110
  version: '0'
94
111
  - !ruby/object:Gem::Dependency
95
112
  name: pry-rails
96
113
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
114
  requirements:
99
- - - ! '>='
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: factory_girl_rails
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: '4.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: '4.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: response_code_matchers
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
100
158
  - !ruby/object:Gem::Version
101
159
  version: '0'
102
160
  type: :development
103
161
  prerelease: false
104
162
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
163
  requirements:
107
- - - ! '>='
164
+ - - '>='
108
165
  - !ruby/object:Gem::Version
109
166
  version: '0'
110
167
  description: Restaurant serves RESTful API on Rails
@@ -114,20 +171,15 @@ executables: []
114
171
  extensions: []
115
172
  extra_rdoc_files: []
116
173
  files:
117
- - app/assets/javascripts/restaurant/application.js
118
- - app/assets/stylesheets/restaurant/application.css
119
- - app/controllers/restaurant/application_controller.rb
120
- - app/helpers/restaurant/application_helper.rb
121
- - app/views/layouts/restaurant/application.html.erb
122
- - config/routes.rb
123
- - lib/restaurant/accept_default.rb
174
+ - lib/restaurant/authentication.rb
175
+ - lib/restaurant/authorization.rb
124
176
  - lib/restaurant/config.rb
125
177
  - lib/restaurant/controller_helper.rb
126
178
  - lib/restaurant/controller_provider.rb
127
- - lib/restaurant/engine.rb
128
179
  - lib/restaurant/model_class_finder.rb
129
180
  - lib/restaurant/params_query_responder.rb
130
181
  - lib/restaurant/params_query_translator.rb
182
+ - lib/restaurant/railtie.rb
131
183
  - lib/restaurant/restful_actions.rb
132
184
  - lib/restaurant/router.rb
133
185
  - lib/restaurant/version.rb
@@ -138,27 +190,26 @@ files:
138
190
  - README.md
139
191
  homepage: https://github.com/r7kamura/restaurant
140
192
  licenses: []
193
+ metadata: {}
141
194
  post_install_message:
142
195
  rdoc_options: []
143
196
  require_paths:
144
197
  - lib
145
198
  required_ruby_version: !ruby/object:Gem::Requirement
146
- none: false
147
199
  requirements:
148
- - - ! '>='
200
+ - - '>='
149
201
  - !ruby/object:Gem::Version
150
202
  version: '0'
151
203
  required_rubygems_version: !ruby/object:Gem::Requirement
152
- none: false
153
204
  requirements:
154
- - - ! '>='
205
+ - - '>='
155
206
  - !ruby/object:Gem::Version
156
207
  version: '0'
157
208
  requirements: []
158
209
  rubyforge_project:
159
- rubygems_version: 1.8.23
210
+ rubygems_version: 2.0.0
160
211
  signing_key:
161
- specification_version: 3
212
+ specification_version: 4
162
213
  summary: Rails RESTful API server plugin
163
214
  test_files: []
164
215
  has_rdoc:
@@ -1,15 +0,0 @@
1
- // This is a manifest file that'll be compiled into application.js, which will include all the files
2
- // listed below.
3
- //
4
- // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
- // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
- //
7
- // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
- // the compiled file.
9
- //
10
- // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
- // GO AFTER THE REQUIRES BELOW.
12
- //
13
- //= require jquery
14
- //= require jquery_ujs
15
- //= require_tree .
@@ -1,13 +0,0 @@
1
- /*
2
- * This is a manifest file that'll be compiled into application.css, which will include all the files
3
- * listed below.
4
- *
5
- * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
- * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
- *
8
- * You're free to add application-wide styles to this file and they'll appear at the top of the
9
- * compiled file, but it's generally better to create a new file per style scope.
10
- *
11
- *= require_self
12
- *= require_tree .
13
- */
@@ -1,4 +0,0 @@
1
- module Restaurant
2
- class ApplicationController < ActionController::Base
3
- end
4
- end
@@ -1,4 +0,0 @@
1
- module Restaurant
2
- module ApplicationHelper
3
- end
4
- end
@@ -1,14 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Restaurant</title>
5
- <%= stylesheet_link_tag "restaurant/application", :media => "all" %>
6
- <%= javascript_include_tag "restaurant/application" %>
7
- <%= csrf_meta_tags %>
8
- </head>
9
- <body>
10
-
11
- <%= yield %>
12
-
13
- </body>
14
- </html>
data/config/routes.rb DELETED
@@ -1,2 +0,0 @@
1
- Restaurant::Engine.routes.draw do
2
- end
@@ -1,7 +0,0 @@
1
- module Restaurant::AcceptDefault
2
- extend ActiveSupport::Concern
3
-
4
- included do
5
- use Rack::AcceptDefault
6
- end
7
- end
@@ -1,5 +0,0 @@
1
- module Restaurant
2
- class Engine < ::Rails::Engine
3
- isolate_namespace Restaurant
4
- end
5
- end