praxis 0.13.0 → 0.14.0
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 +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +15 -2
- data/CHANGELOG.md +54 -1
- data/bin/praxis +49 -2
- data/lib/api_browser/Gruntfile.js +247 -90
- data/lib/api_browser/app/bower_components/angular-mocks/.bower.json +19 -0
- data/lib/api_browser/app/bower_components/angular-mocks/README.md +57 -0
- data/lib/api_browser/app/bower_components/angular-mocks/angular-mocks.js +2193 -0
- data/lib/api_browser/app/bower_components/angular-mocks/bower.json +9 -0
- data/lib/api_browser/app/bower_components/angular-mocks/package.json +27 -0
- data/lib/api_browser/app/bower_components/angular/.bower.json +6 -5
- data/lib/api_browser/app/bower_components/angular/README.md +23 -4
- data/lib/api_browser/app/bower_components/angular/angular-csp.css +6 -0
- data/lib/api_browser/app/bower_components/angular/angular.js +2287 -1597
- data/lib/api_browser/app/bower_components/angular/angular.min.js +212 -205
- data/lib/api_browser/app/bower_components/angular/angular.min.js.gzip +0 -0
- data/lib/api_browser/app/bower_components/angular/angular.min.js.map +3 -3
- data/lib/api_browser/app/bower_components/angular/bower.json +2 -1
- data/lib/api_browser/app/bower_components/angular/package.json +25 -0
- data/lib/api_browser/app/bower_components/showdown/.bower.json +39 -0
- data/lib/api_browser/app/bower_components/showdown/.jshintignore +2 -0
- data/lib/api_browser/app/bower_components/showdown/.travis.yml +8 -0
- data/lib/api_browser/app/bower_components/showdown/Gruntfile.js +100 -0
- data/lib/api_browser/app/bower_components/showdown/README.md +317 -0
- data/lib/api_browser/app/bower_components/showdown/bower.json +26 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/Showdown.js +1606 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/Showdown.js.map +1 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/Showdown.min.js +2 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/extensions/github.min.js +2 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/extensions/github.min.js.map +1 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/extensions/prettify.min.js +2 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/extensions/prettify.min.js.map +1 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/extensions/table.min.js +2 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/extensions/table.min.js.map +1 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/extensions/twitter.min.js +2 -0
- data/lib/api_browser/app/bower_components/showdown/compressed/extensions/twitter.min.js.map +1 -0
- data/lib/api_browser/app/bower_components/showdown/license.txt +34 -0
- data/lib/api_browser/app/bower_components/showdown/package.json +47 -0
- data/lib/api_browser/app/bower_components/showdown/src/extensions/github.js +25 -0
- data/lib/api_browser/app/bower_components/showdown/src/extensions/prettify.js +29 -0
- data/lib/api_browser/app/bower_components/showdown/src/extensions/table.js +106 -0
- data/lib/api_browser/app/bower_components/showdown/src/extensions/twitter.js +42 -0
- data/lib/api_browser/app/bower_components/showdown/src/ng-showdown.js +150 -0
- data/lib/api_browser/app/bower_components/showdown/src/showdown.js +1454 -0
- data/lib/api_browser/app/index.html +6 -4
- data/lib/api_browser/app/js/app.js +1 -2
- data/lib/api_browser/app/js/controllers/action.js +4 -4
- data/lib/api_browser/app/js/controllers/controller.js +1 -1
- data/lib/api_browser/app/js/controllers/menu.js +5 -3
- data/lib/api_browser/app/js/controllers/type.js +5 -5
- data/lib/api_browser/app/js/directives/attribute_description.js +5 -5
- data/lib/api_browser/app/js/directives/attribute_table.js +1 -1
- data/lib/api_browser/app/js/directives/attribute_table_row.js +2 -2
- data/lib/api_browser/app/js/directives/no_container.js +1 -1
- data/lib/api_browser/app/js/directives/request_body.js +5 -5
- data/lib/api_browser/app/js/directives/request_headers.js +3 -6
- data/lib/api_browser/app/js/directives/request_parameters.js +3 -6
- data/lib/api_browser/app/js/directives/type_label.js +4 -5
- data/lib/api_browser/app/js/factories/Documentation.js +4 -4
- data/lib/api_browser/app/js/factories/PayloadTemplates.js +2 -2
- data/lib/api_browser/app/js/factories/TypeTemplates.js +3 -3
- data/lib/api_browser/app/js/filters/markdown.js +6 -0
- data/lib/api_browser/app/js/filters/resource_name.js +2 -2
- data/lib/api_browser/app/sass/modules/_header.scss +2 -7
- data/lib/api_browser/app/sass/{main.scss → praxis.scss} +0 -0
- data/lib/api_browser/app/sass/variables/_bootstrap-variables.scss +370 -367
- data/lib/api_browser/app/views/action.html +2 -2
- data/lib/api_browser/app/views/controller.html +2 -2
- data/lib/api_browser/app/views/directives/attribute_description.html +1 -1
- data/lib/api_browser/app/views/layout.html +2 -11
- data/lib/api_browser/app/views/navbar.html +9 -0
- data/lib/api_browser/app/views/resource/_actions.html +1 -1
- data/lib/api_browser/app/views/type.html +2 -2
- data/lib/api_browser/app/views/type/_details.html +2 -1
- data/lib/api_browser/bower.json +5 -0
- data/lib/api_browser/package.json +18 -7
- data/lib/praxis.rb +8 -3
- data/lib/praxis/action_definition.rb +28 -6
- data/lib/praxis/api_definition.rb +30 -2
- data/lib/praxis/api_general_info.rb +36 -0
- data/lib/praxis/bootloader.rb +1 -0
- data/lib/praxis/collection.rb +34 -0
- data/lib/praxis/controller.rb +7 -0
- data/lib/praxis/dispatcher.rb +3 -0
- data/lib/praxis/links.rb +2 -8
- data/lib/praxis/media_type.rb +6 -24
- data/lib/praxis/media_type_collection.rb +6 -2
- data/lib/praxis/plugin_concern.rb +2 -1
- data/lib/praxis/request.rb +24 -15
- data/lib/praxis/request_stages/request_stage.rb +19 -4
- data/lib/praxis/request_stages/validate_params_and_headers.rb +1 -1
- data/lib/praxis/request_stages/validate_payload.rb +1 -1
- data/lib/praxis/resource_definition.rb +45 -10
- data/lib/praxis/response_definition.rb +46 -27
- data/lib/praxis/restful_doc_generator.rb +94 -7
- data/lib/praxis/simple_media_type.rb +2 -9
- data/lib/praxis/stage.rb +1 -4
- data/lib/praxis/tasks/api_docs.rb +51 -19
- data/lib/praxis/tasks/routes.rb +19 -15
- data/lib/praxis/types/media_type_common.rb +31 -0
- data/lib/praxis/types/multipart.rb +4 -4
- data/lib/praxis/version.rb +1 -1
- data/praxis.gemspec +2 -2
- data/spec/api_browser/factories/documentation_spec.js +50 -0
- data/spec/api_browser/filters/attribute_name_spec.js +23 -0
- data/spec/functional_spec.rb +62 -10
- data/spec/praxis/action_definition_spec.rb +12 -4
- data/spec/praxis/api_definition_spec.rb +159 -0
- data/spec/praxis/api_general_info_spec.rb +36 -0
- data/spec/praxis/bootloader_spec.rb +10 -1
- data/spec/praxis/media_type_collection_spec.rb +46 -53
- data/spec/praxis/media_type_spec.rb +6 -6
- data/spec/praxis/request_stage_spec.rb +7 -2
- data/spec/praxis/request_stages_validate_spec.rb +12 -7
- data/spec/praxis/resource_definition_spec.rb +62 -0
- data/spec/praxis/response_definition_spec.rb +26 -16
- data/spec/praxis/stage_spec.rb +4 -8
- data/spec/praxis/types/collection_spec.rb +144 -0
- data/spec/spec_app/app/controllers/instances.rb +8 -2
- data/spec/spec_app/design/api.rb +11 -0
- data/spec/spec_app/design/media_types/instance.rb +12 -0
- data/spec/spec_app/design/media_types/volume.rb +9 -2
- data/spec/spec_app/design/media_types/volume_snapshot.rb +9 -6
- data/spec/spec_app/design/resources/instances.rb +25 -10
- data/spec/support/spec_media_types.rb +1 -1
- data/spec/support/spec_resource_definitions.rb +2 -0
- data/tasks/thor/app.rb +15 -10
- data/tasks/thor/example.rb +115 -115
- data/tasks/thor/templates/generator/empty_app/.gitignore +2 -0
- data/tasks/thor/templates/generator/empty_app/docs/app.js +1 -0
- data/tasks/thor/templates/generator/empty_app/docs/styles.scss +3 -0
- metadata +50 -9
- data/lib/api_browser/app/css/main.css +0 -4511
- data/lib/praxis/types/collection.rb +0 -17
@@ -6,7 +6,7 @@ module Praxis
|
|
6
6
|
end
|
7
7
|
|
8
8
|
@inspected_types = Set.new
|
9
|
-
API_DOCS_DIRNAME = '
|
9
|
+
API_DOCS_DIRNAME = 'docs/api'
|
10
10
|
|
11
11
|
EXCLUDED_TYPES_FROM_TOP_LEVEL = Set.new([
|
12
12
|
Attributor::Boolean,
|
@@ -81,12 +81,25 @@ module Praxis
|
|
81
81
|
|
82
82
|
add_to_reachable RestfulDocGenerator.inspect_attributes(action_config.params)
|
83
83
|
add_to_reachable RestfulDocGenerator.inspect_attributes(action_config.payload)
|
84
|
+
|
85
|
+
action_config.responses.values.each do |response|
|
86
|
+
add_to_reachable RestfulDocGenerator.inspect_attributes(response.media_type)
|
87
|
+
end
|
84
88
|
end
|
85
89
|
|
86
90
|
end
|
87
91
|
|
88
92
|
# TODO: I think that the "id"/"name" of a resource should be provided by the definition/controller...not derived here
|
89
93
|
def id
|
94
|
+
if @controller_config.controller
|
95
|
+
@controller_config.controller.id
|
96
|
+
else
|
97
|
+
# If an API doesn't quite have the controller defined, let's use the name from the resource definition
|
98
|
+
@controller_config.id
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def name
|
90
103
|
if @controller_config.controller
|
91
104
|
@controller_config.controller.name
|
92
105
|
else
|
@@ -95,6 +108,17 @@ module Praxis
|
|
95
108
|
end
|
96
109
|
end
|
97
110
|
|
111
|
+
def friendly_name
|
112
|
+
# FIXME: is it really about the controller? or the attached resource definition?
|
113
|
+
segments = self.name.split("::")
|
114
|
+
# FIXME: Crappy hack to derive a friendly name
|
115
|
+
if ["Collection","Links"].include? segments.last
|
116
|
+
segments[-2] + segments[-1] # concat the last 2
|
117
|
+
else
|
118
|
+
segments.last
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
98
122
|
def add_to_reachable( found )
|
99
123
|
return if found == nil
|
100
124
|
@reachable_types += found
|
@@ -119,6 +143,7 @@ module Praxis
|
|
119
143
|
write_resources
|
120
144
|
write_types(types_for)
|
121
145
|
write_index(types_for)
|
146
|
+
write_info(types_for)
|
122
147
|
write_templates(types_for)
|
123
148
|
end
|
124
149
|
|
@@ -182,7 +207,7 @@ module Praxis
|
|
182
207
|
FileUtils.mkdir_p dirname unless File.exists? dirname
|
183
208
|
reportable_types = types - EXCLUDED_TYPES_FROM_TOP_LEVEL
|
184
209
|
reportable_types.each do |type|
|
185
|
-
filename = File.join(dirname, "#{type.
|
210
|
+
filename = File.join(dirname, "#{type.id}.json")
|
186
211
|
#puts "Dumping #{type.name} to #{filename}"
|
187
212
|
type_output = type.describe
|
188
213
|
example_data = type.example(type.to_s)
|
@@ -233,12 +258,12 @@ module Praxis
|
|
233
258
|
|
234
259
|
@resources.each do |r|
|
235
260
|
index[r.version] ||= Hash.new
|
236
|
-
info = {controller: r.id}
|
261
|
+
info = {controller: r.id, name: r.name}
|
237
262
|
if r.media_type
|
238
|
-
info[:media_type] = r.media_type.
|
263
|
+
info[:media_type] = r.media_type.id
|
239
264
|
media_types_seen_from_controllers << r.media_type
|
240
265
|
end
|
241
|
-
display_name = r.
|
266
|
+
display_name = r.name.split("::").last
|
242
267
|
index[r.version][display_name] = info
|
243
268
|
end
|
244
269
|
|
@@ -255,9 +280,9 @@ module Praxis
|
|
255
280
|
raise "Display name already taken for version #{version}! #{display_name}"
|
256
281
|
end
|
257
282
|
index[version][display_name] = if type < Praxis::MediaType
|
258
|
-
{media_type: type.
|
283
|
+
{media_type: type.id }
|
259
284
|
else
|
260
|
-
{kind: type.
|
285
|
+
{kind: type.id}
|
261
286
|
end
|
262
287
|
end
|
263
288
|
end
|
@@ -267,6 +292,68 @@ module Praxis
|
|
267
292
|
File.open(filename, 'w') {|f| f.write(JSON.pretty_generate(index))}
|
268
293
|
end
|
269
294
|
|
295
|
+
# Writes an "index" type file inside each version, with some higher level information about the API
|
296
|
+
def write_info( versioned_types )
|
297
|
+
|
298
|
+
resources_by_version = Hash.new do |hash, v|
|
299
|
+
hash[v] = Set.new
|
300
|
+
end
|
301
|
+
types_by_version = Hash.new do |hash, v|
|
302
|
+
hash[v] = Set.new
|
303
|
+
end
|
304
|
+
|
305
|
+
@resources.each do |r|
|
306
|
+
resources_by_version[r.version] << { id: r.id, name: r.name, friendly_name: r.friendly_name}
|
307
|
+
end
|
308
|
+
|
309
|
+
versioned_types.each do |version, types|
|
310
|
+
# # Discard any mediatypes that we've already seen and processed as controller related
|
311
|
+
reportable_types = types - EXCLUDED_TYPES_FROM_TOP_LEVEL
|
312
|
+
# #TODO: think about these special cases, is it needed?
|
313
|
+
# reportable_types.reject!{|type| type < Praxis::Links || type < Praxis::MediaTypeCollection }
|
314
|
+
|
315
|
+
reportable_types.each do |type|
|
316
|
+
segments = type.name.split("::")
|
317
|
+
# FIXME: Crappy hack to derive a friendly name
|
318
|
+
friendly_name = if ["Collection","Links"].include? segments.last
|
319
|
+
segments[-2] + segments[-1] # concat the last 2
|
320
|
+
else
|
321
|
+
segments.last
|
322
|
+
end
|
323
|
+
|
324
|
+
types_by_version[version] << { id: type.id, name: type.name, friendly_name: friendly_name}
|
325
|
+
end
|
326
|
+
end
|
327
|
+
###############################
|
328
|
+
|
329
|
+
diff = resources_by_version.keys - types_by_version.keys - versioned_types.keys
|
330
|
+
raise "!!!!!!!! somehow we have a list of different versions from the types vs. resources seen" unless diff.empty?
|
331
|
+
|
332
|
+
infos = {}
|
333
|
+
versioned_types.each do |version, types|
|
334
|
+
infos[version] = {info:{}}
|
335
|
+
end
|
336
|
+
infos.merge!(ApiDefinition.instance.describe)
|
337
|
+
|
338
|
+
# Add resources and types list
|
339
|
+
versioned_types.keys.each do |v|
|
340
|
+
|
341
|
+
infos[v][:resources] = resources_by_version[v].each_with_object({}) do |element,hash|
|
342
|
+
hash[element[:id]] = { name: element[:name], friendly_name: element[:friendly_name] }
|
343
|
+
end
|
344
|
+
infos[v][:schemas] = types_by_version[v].each_with_object({}) do |element,hash|
|
345
|
+
hash[element[:id]] = { name: element[:name], friendly_name: element[:friendly_name] }
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
versioned_types.each do |version, types|
|
350
|
+
dirname = File.join(@doc_root_dir, version)
|
351
|
+
filename = File.join(dirname, "version_index.json")
|
352
|
+
File.open(filename, 'w') {|f| f.write(JSON.pretty_generate(infos[version]))}
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
|
270
357
|
def write_templates(versioned_types)
|
271
358
|
# Calculate and write top-level (non-versioned) templates
|
272
359
|
top_templates = write_template("")
|
@@ -5,15 +5,8 @@ module Praxis
|
|
5
5
|
self.class.name
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
when String
|
11
|
-
identifier == other_thing
|
12
|
-
when MediaType
|
13
|
-
identifier == other_thing.identifier
|
14
|
-
else
|
15
|
-
raise 'can not compare'
|
16
|
-
end
|
8
|
+
def id
|
9
|
+
self.class.name.gsub("::",'-')
|
17
10
|
end
|
18
11
|
|
19
12
|
def describe(shallow=true)
|
data/lib/praxis/stage.rb
CHANGED
@@ -24,14 +24,13 @@ module Praxis
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def run
|
27
|
-
setup!
|
28
|
-
setup_deferred_callbacks!
|
29
27
|
execute_callbacks(self.before_callbacks)
|
30
28
|
execute
|
31
29
|
execute_callbacks(self.after_callbacks)
|
32
30
|
end
|
33
31
|
|
34
32
|
def setup!
|
33
|
+
setup_deferred_callbacks!
|
35
34
|
end
|
36
35
|
|
37
36
|
def setup_deferred_callbacks!
|
@@ -48,8 +47,6 @@ module Praxis
|
|
48
47
|
end
|
49
48
|
|
50
49
|
def execute
|
51
|
-
raise NotImplementedError, 'Subclass must implement Stage#execute' unless @stages.any?
|
52
|
-
|
53
50
|
@stages.each do |stage|
|
54
51
|
stage.run
|
55
52
|
end
|
@@ -1,30 +1,62 @@
|
|
1
1
|
namespace :praxis do
|
2
|
-
desc "Generate API docs (JSON definitions) for a Praxis App"
|
3
|
-
task :api_docs => [:environment] do |t, args|
|
4
|
-
require 'fileutils'
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
end
|
3
|
+
namespace :docs do
|
4
|
+
path = File.expand_path(File.join(File.dirname(__FILE__), '../../api_browser'))
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
desc "Install dependencies"
|
7
|
+
task :install do
|
8
|
+
unless system("npm install --production", chdir: path)
|
9
|
+
raise Exception.new("NPM Install Failed")
|
10
|
+
end
|
11
|
+
|
12
|
+
docs_dir = File.join(Dir.pwd, 'docs')
|
13
|
+
FileUtils.mkdir_p docs_dir unless File.directory? docs_dir
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
# The doc browser will need to have a minimal app.js and styles.css file at the root
|
16
|
+
# Let's add them if the app has not overriden them
|
17
|
+
js_file = File.join(Dir.pwd, 'docs', 'app.js')
|
18
|
+
scss_file = File.join(Dir.pwd, 'docs', 'styles.scss')
|
19
|
+
template_directory = File.expand_path(File.join(File.dirname(__FILE__), '../../../tasks/thor/templates/generator/empty_app/docs'))
|
20
|
+
|
21
|
+
unless File.exists? js_file
|
22
|
+
FileUtils.cp File.join(template_directory, 'app.js'), js_file
|
18
23
|
end
|
19
|
-
|
20
|
-
|
24
|
+
unless File.exists? scss_file
|
25
|
+
FileUtils.cp File.join(template_directory, 'styles.scss'), scss_file
|
21
26
|
end
|
27
|
+
end
|
22
28
|
|
23
|
-
|
29
|
+
desc "Run API Documentation Browser"
|
30
|
+
task :preview, [:port] => [:install, :generate] do |t, args|
|
31
|
+
doc_port = args[:port] || '9090'
|
32
|
+
exec({'USER_DOCS_PATH' => File.join(Dir.pwd, 'docs'), 'DOC_PORT' => doc_port}, "#{path}/node_modules/.bin/grunt serve --gruntfile '#{path}/Gruntfile.js'")
|
24
33
|
end
|
25
34
|
|
26
|
-
|
27
|
-
|
35
|
+
desc "Build docs that can be shipped"
|
36
|
+
task :build => [:install, :generate] do
|
37
|
+
exec({'USER_DOCS_PATH' => File.join(Dir.pwd, 'docs')}, "#{path}/node_modules/.bin/grunt build --gruntfile '#{path}/Gruntfile.js'")
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Generate API docs (JSON definitions) for a Praxis App"
|
41
|
+
task :generate => [:environment] do |t, args|
|
42
|
+
require 'fileutils'
|
43
|
+
|
44
|
+
Praxis::Blueprint.caching_enabled = false
|
45
|
+
generator = Praxis::RestfulDocGenerator.new(Dir.pwd)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Generate API docs (JSON definitions) for a Praxis App"
|
51
|
+
task :api_docs do
|
52
|
+
STDERR.puts "DEPRECATION: praxis:api_docs is deprecated and will be removed by 1.0. Please use praxis:docs:generate instead."
|
53
|
+
Rake::Task["praxis:docs:generate"].invoke
|
28
54
|
end
|
29
|
-
|
55
|
+
|
56
|
+
desc "Run API Documentation Browser"
|
57
|
+
task :doc_browser, [:port] do |t, args|
|
58
|
+
STDERR.puts "DEPRECATION: praxis:doc_browser is deprecated and will be removed by 1.0. Please use praxis:docs:preview instead. The doc browser now runs on port 9090."
|
59
|
+
Rake::Task["praxis:docs:preview"].invoke
|
60
|
+
end
|
61
|
+
|
30
62
|
end
|
data/lib/praxis/tasks/routes.rb
CHANGED
@@ -4,7 +4,6 @@ namespace :praxis do
|
|
4
4
|
task :routes, [:format] => [:environment] do |t, args|
|
5
5
|
require 'terminal-table'
|
6
6
|
|
7
|
-
|
8
7
|
table = Terminal::Table.new title: "Routes",
|
9
8
|
headings: [
|
10
9
|
"Version", "Path", "Verb",
|
@@ -22,23 +21,28 @@ namespace :praxis do
|
|
22
21
|
|
23
22
|
method_name = method ? "#{method.owner.name}##{method.name}" : 'n/a'
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
24
|
+
row = {
|
25
|
+
resource: resource_definition.name,
|
26
|
+
action: name,
|
27
|
+
implementation: method_name,
|
28
|
+
}
|
29
|
+
|
30
|
+
if action.routes.empty?
|
31
|
+
warn "Warning: No routes defined for #{resource_definition.name}##{name}."
|
32
|
+
rows << row
|
33
|
+
else
|
34
|
+
action.routes.each do |route|
|
35
|
+
rows << row.merge({
|
36
|
+
version: route.version,
|
37
|
+
verb: route.verb,
|
38
|
+
path: route.path,
|
39
|
+
name: route.name,
|
40
|
+
primary: (action.primary_route == route ? 'yes' : '')
|
41
|
+
})
|
36
42
|
end
|
37
43
|
end
|
38
44
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
45
|
+
end
|
42
46
|
|
43
47
|
case args[:format] || "table"
|
44
48
|
when "json"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Praxis
|
2
|
+
module Types
|
3
|
+
|
4
|
+
module MediaTypeCommon
|
5
|
+
extend ::ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def describe(shallow = false)
|
9
|
+
hash = super
|
10
|
+
unless shallow
|
11
|
+
hash.merge!(identifier: @identifier, description: @description)
|
12
|
+
end
|
13
|
+
hash
|
14
|
+
end
|
15
|
+
|
16
|
+
def description(text=nil)
|
17
|
+
@description = text if text
|
18
|
+
@description
|
19
|
+
end
|
20
|
+
|
21
|
+
def identifier(identifier=nil)
|
22
|
+
return @identifier unless identifier
|
23
|
+
# TODO: parse the string and extract things like collection , and format type?...
|
24
|
+
@identifier = identifier
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -28,10 +28,10 @@ module Praxis
|
|
28
28
|
|
29
29
|
super(context, options: options).each do |k,v|
|
30
30
|
body = if v.respond_to?(:dump) && !v.kind_of?(String)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
JSON.pretty_generate(v.dump)
|
32
|
+
else
|
33
|
+
v
|
34
|
+
end
|
35
35
|
|
36
36
|
entity = MIME::Text.new(body)
|
37
37
|
|
data/lib/praxis/version.rb
CHANGED
data/praxis.gemspec
CHANGED
@@ -25,8 +25,8 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_dependency 'activesupport', '>= 3'
|
26
26
|
spec.add_dependency 'mime', '~> 0'
|
27
27
|
spec.add_dependency 'praxis-mapper', '~> 3.3'
|
28
|
-
spec.add_dependency 'praxis-blueprints', '~> 1.
|
29
|
-
spec.add_dependency 'attributor', '~> 2.
|
28
|
+
spec.add_dependency 'praxis-blueprints', '~> 1.3'
|
29
|
+
spec.add_dependency 'attributor', '~> 2.6.0'
|
30
30
|
spec.add_dependency 'thor', '~> 0.18'
|
31
31
|
spec.add_dependency 'terminal-table', '~> 1.4'
|
32
32
|
spec.add_dependency 'harness', '~> 2'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
describe('Documentation service', function() {
|
2
|
+
var $scope, Documentation, $httpBackend;
|
3
|
+
|
4
|
+
beforeEach(angular.mock.module('PraxisDocBrowser'));
|
5
|
+
|
6
|
+
beforeEach(inject(function($rootScope, $injector) {
|
7
|
+
$scope = $rootScope.$new();
|
8
|
+
Documentation = $injector.get('Documentation');
|
9
|
+
$httpBackend = $injector.get('$httpBackend');
|
10
|
+
}));
|
11
|
+
|
12
|
+
afterEach(function() {
|
13
|
+
$httpBackend.verifyNoOutstandingExpectation();
|
14
|
+
$httpBackend.verifyNoOutstandingRequest();
|
15
|
+
});
|
16
|
+
|
17
|
+
describe('#getIndex', function() {
|
18
|
+
var result, response = {
|
19
|
+
'1.0': {
|
20
|
+
'Blogs': {
|
21
|
+
'controller': 'V1-Controllers-Blogs',
|
22
|
+
'name': 'V1::Controllers::Blogs',
|
23
|
+
'media_type': 'V1-MediaTypes-Blog'
|
24
|
+
},
|
25
|
+
'Posts': {
|
26
|
+
'controller': 'V1-ResourceDefinitions-Posts',
|
27
|
+
'name': 'V1::ResourceDefinitions::Posts',
|
28
|
+
'media_type': 'V1-MediaTypes-Post'
|
29
|
+
},
|
30
|
+
'Users': {
|
31
|
+
'controller': 'V1-ResourceDefinitions-Users',
|
32
|
+
'name': 'V1::ResourceDefinitions::Users',
|
33
|
+
'media_type': 'V1-MediaTypes-User'
|
34
|
+
}
|
35
|
+
}
|
36
|
+
};
|
37
|
+
beforeEach(function() {
|
38
|
+
$httpBackend.expectGET('api/index.json').respond(response);
|
39
|
+
Documentation.getIndex().then(function(data) {
|
40
|
+
result = data;
|
41
|
+
});
|
42
|
+
$httpBackend.flush();
|
43
|
+
$scope.$apply();
|
44
|
+
});
|
45
|
+
|
46
|
+
it('returns the index data', function() {
|
47
|
+
expect(result.data).toEqual(response);
|
48
|
+
});
|
49
|
+
});
|
50
|
+
});
|