praxis 0.10.1 → 0.11pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/CHANGELOG.md +47 -10
  4. data/Gemfile +1 -1
  5. data/Guardfile +1 -0
  6. data/bin/praxis +33 -4
  7. data/lib/api_browser/app/css/main.css +0 -3
  8. data/lib/praxis.rb +16 -0
  9. data/lib/praxis/action_definition.rb +16 -18
  10. data/lib/praxis/application.rb +31 -2
  11. data/lib/praxis/bootloader.rb +37 -4
  12. data/lib/praxis/bootloader_stages/environment.rb +3 -7
  13. data/lib/praxis/bootloader_stages/plugin_config_load.rb +20 -0
  14. data/lib/praxis/bootloader_stages/plugin_config_prepare.rb +18 -0
  15. data/lib/praxis/bootloader_stages/plugin_loader.rb +19 -0
  16. data/lib/praxis/bootloader_stages/plugin_setup.rb +13 -0
  17. data/lib/praxis/bootloader_stages/routing.rb +16 -6
  18. data/lib/praxis/callbacks.rb +0 -2
  19. data/lib/praxis/config.rb +3 -2
  20. data/lib/praxis/dispatcher.rb +25 -13
  21. data/lib/praxis/error_handler.rb +16 -0
  22. data/lib/praxis/links.rb +9 -4
  23. data/lib/praxis/media_type_collection.rb +2 -3
  24. data/lib/praxis/notifications.rb +41 -0
  25. data/lib/praxis/plugin.rb +18 -8
  26. data/lib/praxis/plugin_concern.rb +40 -0
  27. data/lib/praxis/request.rb +27 -7
  28. data/lib/praxis/request_stages/action.rb +7 -2
  29. data/lib/praxis/request_stages/response.rb +7 -3
  30. data/lib/praxis/request_stages/validate_payload.rb +7 -1
  31. data/lib/praxis/resource_definition.rb +37 -16
  32. data/lib/praxis/response.rb +1 -0
  33. data/lib/praxis/responses/internal_server_error.rb +13 -8
  34. data/lib/praxis/responses/validation_error.rb +10 -7
  35. data/lib/praxis/restful_doc_generator.rb +312 -0
  36. data/lib/praxis/router.rb +7 -5
  37. data/lib/praxis/skeletor/restful_routing_config.rb +12 -5
  38. data/lib/praxis/stage.rb +5 -1
  39. data/lib/praxis/stats.rb +106 -0
  40. data/lib/praxis/tasks/api_docs.rb +8 -314
  41. data/lib/praxis/version.rb +1 -1
  42. data/praxis.gemspec +4 -1
  43. data/spec/functional_spec.rb +87 -32
  44. data/spec/praxis/action_definition_spec.rb +13 -12
  45. data/spec/praxis/bootloader_spec.rb +12 -5
  46. data/spec/praxis/notifications_spec.rb +23 -0
  47. data/spec/praxis/plugin_concern_spec.rb +21 -0
  48. data/spec/praxis/request_spec.rb +56 -1
  49. data/spec/praxis/request_stages_validate_spec.rb +3 -3
  50. data/spec/praxis/resource_definition_spec.rb +44 -60
  51. data/spec/praxis/responses/internal_server_error_spec.rb +32 -16
  52. data/spec/praxis/restful_routing_config_spec.rb +15 -2
  53. data/spec/praxis/router_spec.rb +5 -3
  54. data/spec/praxis/stats_spec.rb +9 -0
  55. data/spec/praxis_mapper_plugin_spec.rb +71 -0
  56. data/spec/spec_app/app/controllers/instances.rb +12 -0
  57. data/spec/spec_app/app/controllers/volumes.rb +5 -0
  58. data/spec/spec_app/app/models/person.rb +3 -0
  59. data/spec/spec_app/config/active_record.yml +2 -0
  60. data/spec/spec_app/config/authentication.yml +3 -0
  61. data/spec/spec_app/config/authorization.yml +4 -0
  62. data/spec/spec_app/config/environment.rb +28 -1
  63. data/spec/spec_app/config/praxis_mapper.yml +6 -0
  64. data/spec/spec_app/config/sequel_model.yml +2 -0
  65. data/spec/spec_app/config/stats.yml +8 -0
  66. data/spec/spec_app/config/stats.yml.dis +8 -0
  67. data/spec/spec_app/design/resources/instances.rb +53 -16
  68. data/spec/spec_app/design/resources/volumes.rb +13 -2
  69. data/spec/spec_helper.rb +14 -0
  70. data/spec/support/spec_authentication_plugin.rb +126 -0
  71. data/spec/support/spec_authorization_plugin.rb +95 -0
  72. data/spec/support/spec_praxis_mapper_plugin.rb +157 -0
  73. data/tasks/loader.thor +6 -0
  74. data/tasks/thor/app.rb +48 -0
  75. data/tasks/thor/example.rb +283 -0
  76. data/tasks/thor/templates/generator/empty_app/.gitignore +3 -0
  77. data/tasks/thor/templates/generator/empty_app/.rspec +1 -0
  78. data/tasks/thor/templates/generator/empty_app/Gemfile +29 -0
  79. data/tasks/thor/templates/generator/empty_app/Guardfile +3 -0
  80. data/tasks/thor/templates/generator/empty_app/README.md +4 -0
  81. data/tasks/thor/templates/generator/empty_app/Rakefile +25 -0
  82. data/tasks/thor/templates/generator/empty_app/app/models/.empty_directory +0 -0
  83. data/tasks/thor/templates/generator/empty_app/app/models/.gitkeep +0 -0
  84. data/tasks/thor/templates/generator/empty_app/app/responses/.empty_directory +0 -0
  85. data/tasks/thor/templates/generator/empty_app/app/responses/.gitkeep +0 -0
  86. data/tasks/thor/templates/generator/empty_app/app/v1/controllers/.empty_directory +0 -0
  87. data/tasks/thor/templates/generator/empty_app/app/v1/controllers/.gitkeep +0 -0
  88. data/tasks/thor/templates/generator/empty_app/config.ru +7 -0
  89. data/tasks/thor/templates/generator/empty_app/config/environment.rb +17 -0
  90. data/tasks/thor/templates/generator/empty_app/config/rainbows.rb +57 -0
  91. data/tasks/thor/templates/generator/empty_app/design/api.rb +0 -0
  92. data/tasks/thor/templates/generator/empty_app/design/response_templates/.empty_directory +0 -0
  93. data/tasks/thor/templates/generator/empty_app/design/response_templates/.gitkeep +0 -0
  94. data/tasks/thor/templates/generator/empty_app/design/v1/media_types/.empty_directory +0 -0
  95. data/tasks/thor/templates/generator/empty_app/design/v1/media_types/.gitkeep +0 -0
  96. data/tasks/thor/templates/generator/empty_app/design/v1/resources/.empty_directory +0 -0
  97. data/tasks/thor/templates/generator/empty_app/design/v1/resources/.gitkeep +0 -0
  98. data/tasks/thor/templates/generator/empty_app/spec/spec_helper.rb +18 -0
  99. metadata +97 -6
  100. data/tasks/praxis_app_generator.thor +0 -307
data/tasks/loader.thor ADDED
@@ -0,0 +1,6 @@
1
+ require 'thor'
2
+
3
+ files = Dir[File.join(File.dirname(__FILE__), "thor/*.rb")]
4
+ files.each do |f|
5
+ require File.expand_path(f)
6
+ end
data/tasks/thor/app.rb ADDED
@@ -0,0 +1,48 @@
1
+ module PraxisGen
2
+ class App < Thor
3
+ include Thor::Actions
4
+
5
+ namespace "praxis:app"
6
+ def self.source_root
7
+ File.dirname(__FILE__) + "/templates/generator/empty_app"
8
+ end
9
+
10
+ argument :app_name, required: true
11
+ desc "new", "Generates a blank new app under <app_name> (with a full skeleton ready to start coding)"
12
+
13
+ # Generator for a blank new app (with a full skeleton ready to get you going)
14
+ def new
15
+ puts "Creating new blank Praxis app under #{app_name}"
16
+ create_root_files
17
+ create_config
18
+ create_app
19
+ create_design
20
+ create_spec
21
+ end
22
+
23
+ private
24
+ def create_root_files
25
+ ['config.ru','Gemfile','Guardfile','Rakefile','README.md'].each do |file|
26
+ copy_file file, "#{app_name}/#{file}"
27
+ end
28
+ end
29
+
30
+ def create_config
31
+ copy_file "config/environment.rb", "#{app_name}/config/environment.rb"
32
+ copy_file "config/rainbows.rb", "#{app_name}/config/rainbows.rb"
33
+ end
34
+
35
+ def create_app
36
+ directory "app", "#{app_name}/app", :recursive => true
37
+ end
38
+
39
+ def create_design
40
+ directory "design", "#{app_name}/design", :recursive => true
41
+ end
42
+
43
+ def create_spec
44
+ directory "spec", "#{app_name}/spec", :recursive => true
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,283 @@
1
+
2
+ module PraxisGen
3
+ class Example < Thor
4
+ include Thor::Actions
5
+
6
+ namespace "praxis:example"
7
+
8
+ argument :app_name, required: true
9
+ desc "new", "Generates a new 'hello world' example application under an <app_name> directory"
10
+
11
+ def new
12
+ puts "GENERATION COMMENTED!! (for #{app_name})"
13
+ # Fix weird symbols in the app name (if they are)
14
+ @app_name = app_name.downcase.gsub(/[^a-z0-9_\/.]/, '')
15
+ # Generate a new app
16
+ empty_directory path('app')
17
+ empty_directory path('design')
18
+ empty_directory path('lib')
19
+ empty_directory path('spec')
20
+ generate_config_environment_rb
21
+ generate_gemfile
22
+ generate_rakefile
23
+ generate_config_ru
24
+ generate_app_definitions_hello_world
25
+ generate_app_controllers_hello_world
26
+ #
27
+ puts
28
+ puts "To run the example application:"
29
+ puts
30
+ puts " # terminal 1:"
31
+ puts " cd #{app_name}"
32
+ puts " bundle"
33
+ puts " rackup -p 8888"
34
+ puts
35
+ puts " # terminal 2:"
36
+ puts " curl -i http://localhost:8888/api/hello -H 'X-Api-Version: 1.0' -X GET # Index"
37
+ puts " curl -i http://localhost:8888/api/hello/2 -H 'X-Api-Version: 1.0' -X GET # Show"
38
+ puts " curl -i http://localhost:8888/api/hello/2 -H 'X-Api-Version: 2.0' -X GET # NotFound Error"
39
+ nil
40
+ end
41
+ private
42
+ # Returns relative path for the new application
43
+ #
44
+ # @return [String]
45
+ #
46
+ # @example
47
+ # # > /praxis generate My-test_praxisApp
48
+ # app_dir_pathname #=> 'mytest_praxisapp'
49
+ #
50
+ #
51
+ def app_dir_pathname
52
+ @app_dir_pathname ||= Pathname.new(app_name)
53
+ end
54
+
55
+
56
+ # Returns path string built from the set of the given strings
57
+ #
58
+ # @param [String,Array] strings
59
+ #
60
+ # @return [String]
61
+ #
62
+ # @example
63
+ # path('a', 'b', 'c') #=> 'my_test_app/a/b/c'
64
+ #
65
+ def path(*strings)
66
+ app_dir_pathname.join(*strings).to_s
67
+ end
68
+
69
+
70
+ # Creates './config/environment.rb' file
71
+ #
72
+ # @return [void]
73
+ #
74
+ def generate_config_environment_rb
75
+ create_file path('config/environment.rb') do
76
+ <<-RUBY
77
+ # Main entry point - DO NOT MODIFY THIS FILE
78
+ ENV['RACK_ENV'] ||= 'development'
79
+
80
+ Bundler.require(:default, ENV['RACK_ENV'])
81
+
82
+ # Default application layout.
83
+ # NOTE: This layout need NOT be specified explicitly.
84
+ # It is provided just for illustration.
85
+ Praxis::Application.instance.layout do
86
+ map :initializers, 'config/initializers/**/*'
87
+ map :lib, 'lib/**/*'
88
+ map :design, 'design/' do
89
+ map :api, 'api.rb'
90
+ map :media_types, '**/media_types/**/*'
91
+ map :resources, '**/resources/**/*'
92
+ end
93
+ map :app, 'app/' do
94
+ map :models, 'models/**/*'
95
+ map :controllers, '**/controllers/**/*'
96
+ map :responses, '**/responses/**/*'
97
+ end
98
+ end
99
+ RUBY
100
+ end
101
+ nil
102
+ end
103
+
104
+
105
+ # Creates './Gemfile' file
106
+ #
107
+ # @return [void]
108
+ #
109
+ def generate_gemfile
110
+ create_file path('Gemfile') do
111
+ <<-RUBY
112
+ source 'https://rubygems.org'
113
+
114
+ gem 'praxis'
115
+ gem 'rack', '~> 1.0'
116
+ gem 'rake'
117
+
118
+ group :development, :test do
119
+ gem 'rspec'
120
+ end
121
+ RUBY
122
+ end
123
+ nil
124
+ end
125
+
126
+
127
+ # Creates './Rakefile' file
128
+ #
129
+ # @return [void]
130
+ #
131
+ def generate_rakefile
132
+ create_file path('Rakefile') do
133
+ <<-RUBY
134
+ require 'praxis'
135
+ require 'praxis/tasks'
136
+ RUBY
137
+ end
138
+ nil
139
+ end
140
+
141
+
142
+ # Creates './config.ru' file
143
+ #
144
+ # @return [void]
145
+ #
146
+ def generate_config_ru
147
+ create_file path('config.ru') do
148
+ <<-RUBY
149
+ #\ -p 8888
150
+
151
+ require 'bundler/setup'
152
+ require 'praxis'
153
+
154
+ application = Praxis::Application.instance
155
+ application.logger = Logger.new(STDOUT)
156
+ application.setup
157
+
158
+ run application
159
+ RUBY
160
+ end
161
+ nil
162
+ end
163
+
164
+
165
+ def generate_app_definitions_hello_world
166
+ create_file path('design/api.rb') do
167
+ <<-RUBY
168
+ # Use this file to define your response templates and traits.
169
+ #
170
+ # For example, to define a response template:
171
+ # response_template :custom do |media_type:|
172
+ # status 200
173
+ # media_type media_type
174
+ # end
175
+ Praxis::ApiDefinition.define do
176
+ trait :versionable do
177
+ headers do
178
+ key "X-Api-Version", String, values: ['1.0'], required: true
179
+ end
180
+ end
181
+ end
182
+ RUBY
183
+ end
184
+
185
+ create_file path('design/resources/hello.rb') do
186
+ <<-RUBY
187
+ module V1
188
+ module ApiResources
189
+ class Hello
190
+ include Praxis::ResourceDefinition
191
+
192
+ media_type V1::MediaTypes::Hello
193
+ version '1.0'
194
+
195
+ routing do
196
+ prefix '/api/hello'
197
+ end
198
+
199
+ action :index do
200
+ use :versionable
201
+
202
+ routing do
203
+ get ''
204
+ end
205
+ response :ok
206
+ end
207
+
208
+ action :show do
209
+ use :versionable
210
+
211
+ routing do
212
+ get '/:id'
213
+ end
214
+ params do
215
+ attribute :id, Integer, required: true, min: 0
216
+ end
217
+ response :ok
218
+ response :not_found
219
+ end
220
+ end
221
+ end
222
+ end
223
+ RUBY
224
+ end
225
+
226
+ create_file path('design/media_types/hello.rb') do
227
+ <<-RUBY
228
+ module V1
229
+ module MediaTypes
230
+ class Hello < Praxis::MediaType
231
+
232
+ identifier 'application/json'
233
+
234
+ attributes do
235
+ attribute :string, String
236
+ end
237
+
238
+ view :default do
239
+ attribute :string
240
+ end
241
+ end
242
+ end
243
+ end
244
+ RUBY
245
+ end
246
+ end
247
+
248
+
249
+ def generate_app_controllers_hello_world
250
+ create_file path('app/controllers/hello.rb') do
251
+ <<-RUBY
252
+ module V1
253
+ class Hello
254
+ include Praxis::Controller
255
+
256
+ implements V1::ApiResources::Hello
257
+
258
+ HELLO_WORLD = [ 'Hello world!', 'Привет мир!', 'Hola mundo!', '你好世界!', 'こんにちは世界!' ]
259
+
260
+ def index(**params)
261
+ response.headers['Content-Type'] = 'application/json'
262
+ response.body = HELLO_WORLD.to_json
263
+ response
264
+ end
265
+
266
+ def show(id:, **other_params)
267
+ hello = HELLO_WORLD[id]
268
+ if hello
269
+ response.body = { id: id, data: hello }
270
+ else
271
+ self.response = Praxis::Responses::NotFound.new
272
+ end
273
+ response.headers['Content-Type'] = 'application/json'
274
+ response
275
+ end
276
+ end
277
+ end
278
+ RUBY
279
+ end
280
+ end
281
+
282
+ end
283
+ end
@@ -0,0 +1,3 @@
1
+ log
2
+ .bundle
3
+ api_docs
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,29 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'praxis', github: 'rightscale/praxis'
4
+ gem 'attributor', github: 'rightscale/attributor'
5
+ gem 'praxis-blueprints', github: 'rightscale/praxis-blueprints'
6
+
7
+ gem 'rainbows', require: false
8
+ gem 'rake'
9
+ gem 'pry'
10
+ gem 'pry-byebug'
11
+
12
+ group :development, :test do
13
+ gem "rack-test", :require => "rack/test"
14
+ gem "rspec" # needed for rake task
15
+ gem 'rspec-its'
16
+ gem 'rspec-collection_matchers'
17
+
18
+ gem 'foreman', :require => false
19
+
20
+ platform :mri_19, :mri_20 do
21
+ gem 'shotgun', :require => false
22
+ gem "guard"
23
+ gem "guard-rspec"
24
+ end
25
+ end
26
+
27
+ platform :jruby do
28
+ gem 'jruby-openssl'
29
+ end
@@ -0,0 +1,3 @@
1
+ guard :rspec do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ end
@@ -0,0 +1,4 @@
1
+ Sample Blog Application
2
+ =======================
3
+
4
+
@@ -0,0 +1,25 @@
1
+ require 'bundler/setup'
2
+
3
+ ENV['RACK_ENV'] ||= 'development'
4
+ Bundler.require(:default, ENV['RACK_ENV'])
5
+
6
+ require 'praxis/tasks'
7
+
8
+ task :default => :spec
9
+
10
+ # load up the Praxis app
11
+ task :environment do
12
+ Praxis::Application.instance.setup
13
+ end
14
+
15
+ desc "console"
16
+ task :console => :environment do
17
+ require 'pry'
18
+ require 'pry-byebug'
19
+ pry
20
+ end
21
+
22
+ require 'rspec/core/rake_task'
23
+ RSpec::Core::RakeTask.new(:spec)
24
+
25
+ Dir["lib/tasks/**/*.rake"].each { |ext| load ext }
@@ -0,0 +1,7 @@
1
+ # -p 8888
2
+
3
+ ENV['RACK_ENV'] ||= 'development'
4
+ Bundler.setup(:default, ENV['RACK_ENV'])
5
+ Bundler.require(:default, ENV['RACK_ENV'])
6
+
7
+ run Praxis::Application.instance.setup
@@ -0,0 +1,17 @@
1
+ #
2
+ #Praxis::Application.instance.layout do
3
+ # map :initializers, 'config/initializers/**/*'
4
+ # map :lib, 'lib/**/*'
5
+ # map :design, 'design/' do
6
+ # map :api, 'api.rb'
7
+ # map :media_types, '**/media_types/**/*'
8
+ # map :resources, '**/resources/**/*'
9
+ # end
10
+ # map :app, 'app/' do
11
+ # map :models, 'models/**/*'
12
+ # map :controllers, '**/controllers/**/*'
13
+ # map :responses, '**/responses/**/*'
14
+ # end
15
+ #end
16
+ #
17
+ #