restaurant 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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