lurker 0.6.9 → 0.6.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -2
  3. data.tar.gz.sig +0 -0
  4. data/README.md +8 -1
  5. data/lib/lurker.rb +9 -1
  6. data/lib/lurker/cli.rb +148 -129
  7. data/lib/lurker/endpoint.rb +7 -3
  8. data/lib/lurker/json/schema.rb +12 -3
  9. data/lib/lurker/json/{writter.rb → writer.rb} +2 -2
  10. data/lib/lurker/presenters/base_presenter.rb +9 -34
  11. data/lib/lurker/presenters/endpoint_presenter.rb +16 -6
  12. data/lib/lurker/presenters/service_presenter.rb +29 -5
  13. data/lib/lurker/rendering_controller.rb +14 -7
  14. data/lib/lurker/service.rb +18 -12
  15. data/lib/lurker/templates/documentation.md.tt +1 -0
  16. data/lib/lurker/templates/javascripts/lurker.js +1 -1
  17. data/lib/lurker/templates/layouts/application.html.erb +54 -57
  18. data/lib/lurker/templates/layouts/print.html.erb +29 -0
  19. data/lib/lurker/templates/lurker/rendering/_endpoint.html.erb +36 -0
  20. data/lib/lurker/templates/lurker/rendering/_service.html.erb +7 -0
  21. data/lib/lurker/templates/lurker/rendering/_submit_form.html.erb +16 -16
  22. data/lib/lurker/templates/lurker/rendering/all.html.erb +5 -0
  23. data/lib/lurker/templates/lurker/rendering/index.html.erb +1 -10
  24. data/lib/lurker/templates/lurker/rendering/show.html.erb +1 -37
  25. data/lib/lurker/templates/public/application.css +1 -1
  26. data/lib/lurker/templates/public/application.js +1 -1
  27. data/lib/lurker/templates/stylesheets/application.scss +3 -0
  28. data/lib/lurker/version.rb +1 -1
  29. data/tasks/build.rake +2 -2
  30. data/tasks/generate.rake +2 -0
  31. data/templates/lurker_app.rb +0 -1
  32. metadata +8 -4
  33. metadata.gz.sig +0 -0
  34. data/lib/lurker/templates/meta_service.md.erb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9643afaa53257cb69053c126c15700b8d763332e
4
- data.tar.gz: 54247852acb557093f2bde400adf1deffc8b6da9
3
+ metadata.gz: fb9c0414b141e2d48b9c7a6d03be6e671a6ad3ed
4
+ data.tar.gz: 777ba4fb742083bfaabeb5c912be901ae51f9bfc
5
5
  SHA512:
6
- metadata.gz: 79d5676e91e53272c072ca3ca2caf5b307cce5f82c299e1e61d6e7d0cfb9369f7ee8547f53607f8d6adf6b530fab63bbdd2099e7a14dfa8f6740dbb561598ca9
7
- data.tar.gz: fababb8b949417a403726a0b8901fde3c48c9b600f3db35fc72e284f07f094af06fdc83627d00485d7fc62cb6b1d90322ba2a8094d44bf87221c05e96de34515
6
+ metadata.gz: ad1be4d40f3a1558527e61d2bce3b22eb9050f8264189b54d5a2346763a86c7559dd0b6c245ec71a5a8a8100f14d62245d30236d227af8ba91e6de0cb5fcf799
7
+ data.tar.gz: cd34824f79c859a1cc27eea9a0d7b9f23af8f58bcfe680037fae0a151c6a49d593f3c0990677cc8d9288d08e0d9e4ca5dba112495039f96b306d33a766f0eee7
@@ -1,2 +1 @@
1
- hs{}�֗�sn{��#Hǥ$�B3��Ը�{8F2�O)���c�����6�� ��OvK���}*1���ߑ�཮u]8W��?L[��S��݌V]�!{}�]��'J�DQ��=��%�J�� ��vD��Ry2g�Ϳ�2��Q`:Uig�Z�3����&5ʸ�=d'�M��T|+�O><�)�]�~d����Ɯ�mx��'�܀�j���l
2
- �������j��ML�l،��x�gy�_��mp0(�
1
+ Ҕ�+Il�$� 0٫#�bA�������j�q����0��������O§�i(����YN/���:��/+�Zm���5/(��d��2Zk1��p�Ùo|J+w�. �[�\����΀fE*�^��bs'����$ݝ�_� u�� ���v6MpfQ�QϞ���d��O��6��!���7������#�q�`˼9����㣸А��5���~�x�<8V�l��5۩�_k�BL��uS���������
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -92,6 +92,13 @@ The generation of live-documentation is pretty simple:
92
92
 
93
93
  For different document root or serving URL prefix use `-o` and `-u` options accordingly.
94
94
 
95
+ If you want to provide additional documentation for your API (and you probably should),
96
+ you can use separate Markdown files in the schema folder. To generate documentation
97
+ stubs for the current schema:
98
+
99
+ bin/lurker init_docs # generate documentation stubs for the current schema
100
+
101
+
95
102
  Let's run your `rails s` and visit [http://localhost:3000/lurker/](http://localhost:3000/lurker/)
96
103
  (or see [demo][demo_app2] for example)
97
104
 
@@ -217,7 +224,7 @@ This gem is heavily inspired by them. Thanks, @square & @fredwu
217
224
  Also thanks to
218
225
 
219
226
  - [Andrey Deryabin][aderyabin] for advice
220
- - [React.js][reactjs] for two-way binding
227
+ - [React.js][reactjs] for reactive UI
221
228
  - [highlight.js][hljs] for syntax highlighting
222
229
 
223
230
  [aderyabin]: https://twitter.com/aderyabin
@@ -28,6 +28,14 @@ module Lurker
28
28
  @service_path || DEFAULT_SERVICE_PATH
29
29
  end
30
30
 
31
+ def self.valid_service_path?
32
+ Dir.exist? service_path
33
+ end
34
+
35
+ def self.service
36
+ @service ||= Lurker::Service.new(service_path)
37
+ end
38
+
31
39
  def self.decide_success_with(&block)
32
40
  @success_block = block
33
41
  end
@@ -65,7 +73,7 @@ require 'lurker/presenters/schema_presenter'
65
73
  require 'lurker/presenters/response_code_presenter'
66
74
  require 'lurker/json'
67
75
  require 'lurker/json/reader'
68
- require 'lurker/json/writter'
76
+ require 'lurker/json/writer'
69
77
  require 'lurker/json/orderer'
70
78
  require 'lurker/json/parser'
71
79
  require 'lurker/json/parser/expertise'
@@ -5,6 +5,9 @@ require 'lurker'
5
5
  require 'active_support/inflector'
6
6
 
7
7
  module Lurker
8
+ BUNDLED_TEMPLATES_PATH = Pathname.new('../templates').expand_path(__FILE__)
9
+ BUNDLED_ASSETS_PATH = Pathname.new('../templates/public').expand_path(__FILE__)
10
+
8
11
  # A Thor::Error to be thrown when an lurker directory is not found
9
12
  class NotFound < Thor::Error; end
10
13
 
@@ -12,140 +15,124 @@ module Lurker
12
15
  class Cli < Thor
13
16
  include Thor::Actions
14
17
 
15
- attr_accessor :origin_path, :content
18
+ attr_accessor :content
19
+
20
+ def self.templates_root
21
+ options[:template].present? ? Pathname.new(options[:templates]).expand_path : Lurker::BUNDLED_TEMPLATES_PATH
22
+ end
16
23
 
17
- def self.source_root
18
- File.expand_path("../templates", __FILE__)
24
+ def self.assets_root
25
+ options[:assets].present? ? Pathname.new(options[:assets]).expand_path : Lurker::BUNDLED_ASSETS_PATH
19
26
  end
20
27
 
21
- def self.precompiled_static_root
22
- File.expand_path("../templates/public", __FILE__)
28
+ source_root(templates_root)
29
+
30
+ desc 'init_docs [LURKER_PATH]', 'Create documentation stubs for service and endpoints'
31
+
32
+ def init_docs(lurker_path=Lurker::DEFAULT_SERVICE_PATH)
33
+ say_status nil, 'Creating documentation stubs'
34
+
35
+ setup_schema_root! lurker_path
36
+
37
+ schemas = Lurker.service.endpoints.map(&:schema) << Lurker.service.schema
38
+ schemas.each do |schema|
39
+ rel_path = Pathname.new(schema.documentation_uri).relative_path_from(Pathname.getwd)
40
+ template 'documentation.md.tt', schema.documentation_uri, skip: true, path: rel_path
41
+ end
23
42
  end
24
43
 
25
- desc "convert [LURKER_PATH]", "Convert lurker to HTML"
26
- method_option :rails, :type => :boolean, :desc => "Includes Rails environment"
27
- method_option :exclude, :aliases => "-e", :desc => "Select endpoints by given regexp, if NOT matching prefix"
28
- method_option :select, :aliases => "-s", :desc => "Select endpoints by given regexp, matching prefix"
29
- method_option :output, :aliases => "-o", :desc => "Output path", :default => "public"
30
- method_option :url_base_path, :aliases => "-u", :desc => "URL base path", :default => Lurker::DEFAULT_URL_BASE
31
- method_option :format, :aliases => "-f", :desc => "Format in html or pdf, defaults to html", :default => "html"
32
- method_option :templates, :aliases => "-t", :desc => "Template overrides path"
33
- method_option :content, :aliases => "-c", :desc => "Content to be rendered into html-docs main page"
44
+ desc 'convert [LURKER_PATH]', 'Convert lurker to HTML'
45
+ option :rails, type: :boolean, desc: 'Includes Rails environment'
46
+ option :exclude, aliases: '-e', desc: 'Select endpoints by given regexp, if NOT matching prefix'
47
+ option :select, aliases: '-s', desc: 'Select endpoints by given regexp, matching prefix'
48
+ option :output, aliases: '-o', desc: 'Output path', default: 'public'
49
+ option :url_base_path, aliases: '-u', desc: 'URL base path', default: Lurker::DEFAULT_URL_BASE
50
+ option :templates, aliases: '-t', desc: 'Template overrides path'
51
+ option :assets, aliases: '-a', desc: 'Assets overrides path'
52
+ option :format, aliases: '-f', desc: 'Format in html or pdf, defaults to html', default: 'html'
53
+ option :content, aliases: '-c', desc: 'Content to be rendered into html-docs main page'
54
+
34
55
  def convert(lurker_path=Lurker::DEFAULT_SERVICE_PATH)
35
56
  say_status nil, "Converting lurker to #{options[:format]}"
36
57
 
37
- self.content = get_content(options[:content])
38
- self.origin_path = File.expand_path(lurker_path)
39
- raise Lurker::NotFound.new(origin_path) unless has_valid_origin?
40
- say_status :using, lurker_path
41
-
42
- FileUtils.mkdir_p(output_path)
43
- say_status :inside, output_path
58
+ setup_schema_root! lurker_path
59
+ require "#{Dir.pwd}/config/environment" if options[:rails]
44
60
 
45
- if options[:rails]
46
- require "#{Dir.pwd}/config/environment"
61
+ # for backward compatibility
62
+ if options[:content]
63
+ Lurker.service.documentation = open(File.expand_path(options[:content])).read
47
64
  end
48
65
 
49
- if options[:format] == 'pdf'
50
- convert_to_pdf
51
- else
52
- convert_to_html
66
+ setup_rendering_engine!
67
+
68
+ inside(output_path) do
69
+ say_status :inside, output_path
70
+ prepare_assets!
71
+ if options[:format] == 'pdf'
72
+ convert_to_pdf
73
+ else
74
+ convert_to_html
75
+ end
76
+ cleanup_assets!
53
77
  end
54
78
  end
55
79
 
56
80
  no_tasks do
57
81
  def convert_to_pdf
58
82
  Lurker.safe_require('pdfkit')
59
- css = File.expand_path('application.css', self.class.precompiled_static_root)
60
- inside(output_path) do
61
- service_presenters.each do |service_presenter|
62
- html = "<html><body>"
63
- service_presenter.endpoints.each do |endpoint_prefix_group|
64
- endpoint_prefix_group.each do |endpoint_presenter|
65
- html << endpoint_presenter.to_html(layout: false)
66
- end
67
- end
68
- html << "</body></html>"
69
- kit = PDFKit.new(html, :page_size => 'Letter')
70
- kit.stylesheets << css
71
- url_name = ActiveSupport::Inflector.parameterize(service_presenter.name, '_')
72
- create_file("#{url_name}.pdf", kit.to_pdf, force: true)
73
- end
74
- end
83
+ kit = PDFKit.new(service_presenter.to_print)
84
+ kit.stylesheets << assets['application.css']
85
+ create_file "#{service_presenter.url_name}.pdf", kit.to_pdf, force: true
75
86
  end
76
87
 
77
88
  def convert_to_html
78
- inside(output_path) do
79
- # js, css, fonts
80
- static = []
81
- Dir["#{self.class.precompiled_static_root}/*"].each do |fname|
82
- if match = fname.match(/application\.(js|css)$/)
83
- sha1 = Digest::SHA1.hexdigest(open(fname).read)
84
- html_options.merge! match[1] => sha1
85
- static << (new_name = "application-#{sha1}.#{match[1]}")
86
- FileUtils.cp_r fname, new_name
87
- spawn "cat #{new_name} | gzip -9 > #{new_name}.gz"
88
- else
89
- FileUtils.cp_r fname, Pathname.new(fname).basename.to_s
90
- end
91
- end
92
-
93
- service_presenters.each do |service_presenter|
94
- create_file("index.html", service_presenter.to_html, force: true)
95
-
96
- service_presenter.endpoints.each do |endpoint_prefix_group|
97
- endpoint_prefix_group.each do |endpoint_presenter|
98
- create_file(endpoint_presenter.relative_path, endpoint_presenter.to_html, force: true)
99
- end
100
- end
101
- end
89
+ create_file 'index.html', service_presenter.to_html, force: true
102
90
 
103
- # cleanup
104
- Dir.glob("*.js").each do |fname|
105
- FileUtils.rm fname unless static.include? fname
106
- end
107
- Dir.glob("*.css").each do |fname|
108
- FileUtils.rm fname unless static.include? fname
109
- end
110
- Dir.glob("*.gz").each do |fname|
111
- FileUtils.rm fname unless static.include? fname.sub(/\.gz/, '')
91
+ service_presenter.endpoints.each do |endpoint_prefix_group|
92
+ endpoint_prefix_group.each do |endpoint_presenter|
93
+ create_file(endpoint_presenter.relative_path, endpoint_presenter.to_html, force: true)
112
94
  end
113
95
  end
114
96
  end
115
97
 
116
- def output_path
117
- "#{output_prefix}/#{url_base_path}"
98
+ def setup_schema_root!(path)
99
+ Lurker.service_path = File.expand_path(path)
100
+ raise Lurker::NotFound.new(Lurker.service_path) unless Lurker.valid_service_path?
101
+ say_status :using, path
118
102
  end
119
103
 
120
- def output_prefix
121
- if explicit = options[:output]
122
- explicit.sub(/\/?#{url_base_path}\/?$/, '')
123
- elsif File.exists? "public"
124
- "public"
125
- else
126
- raise "Please, run it from `Rails.root` or pass `-o` option"
127
- end
104
+ def setup_rendering_engine!
105
+ I18n.config.enforce_available_locales = true
106
+ Lurker::RenderingController.prepend_view_path templates_root
107
+ Lurker::RenderingController.config.assets_dir = assets_root
128
108
  end
129
109
 
130
- def template_path
131
- @template_path ||=
132
- if options[:templates]
133
- File.expand_path(options[:templates])
134
- else
135
- File.expand_path("../templates", origin_path)
136
- end
110
+ def prepare_assets!
111
+ directory assets_root, '.', exclude_pattern: /application\.(js|css)$/
112
+ digest_asset!('application.js')
113
+ digest_asset!('application.css')
137
114
  end
138
115
 
139
- def has_valid_origin?
140
- origin.directory?
116
+ def cleanup_assets!
117
+ actual = assets.values
118
+ Dir.glob('*.{js,css,gz}').each do |fname|
119
+ remove_file fname unless actual.include? fname.sub(/\.gz/, '')
120
+ end
141
121
  end
142
122
 
143
- def service_presenters
144
- @service_presenters ||= services.map do |service|
145
- Lurker::ServicePresenter.new(service, html_options, &filtering_block)
123
+ def digest_asset!(name)
124
+ if (asset_path = assets_root + name).exist?
125
+ digest_path = asset_digest_path(asset_path).basename
126
+ assets[asset_path.basename.to_s] = digest_path.to_s
127
+ copy_file asset_path, digest_path, skip: true
128
+ spawn "cat #{digest_path} | gzip -9 > #{digest_path}.gz"
146
129
  end
147
130
  end
148
131
 
132
+ def service_presenter
133
+ @service_presenter ||= Lurker::ServicePresenter.new(Lurker.service, html_options, &filtering_block)
134
+ end
135
+
149
136
  def filtering_block
150
137
  if options['select'].present?
151
138
  select = /#{options['select']}/
@@ -167,29 +154,80 @@ module Lurker
167
154
 
168
155
  def html_options
169
156
  @html_options ||= {
170
- :static_html => true,
171
- :url_base_path => url_base_path.prepend('/'),
172
- :template_directory => template_path,
173
- :html_directory => output_path,
174
- :content => self.content,
175
- :footer => (`git rev-parse --short HEAD`.to_s.strip rescue ""),
176
- :lurker => gem_info
157
+ static_html: true,
158
+ url_base_path: url_base_path.prepend('/'),
159
+ template_directory: templates_root,
160
+ assets_directory: assets_root,
161
+ assets: assets,
162
+ html_directory: output_path,
163
+ footer: footer,
164
+ lurker: gem_info
177
165
  }
178
166
  end
179
167
  end
180
168
 
181
169
  private
182
170
 
171
+ def output_path
172
+ "#{output_prefix}/#{url_base_path}"
173
+ end
174
+
175
+ def output_prefix
176
+ if explicit = options[:output]
177
+ explicit.sub(/\/?#{url_base_path}\/?$/, '')
178
+ elsif File.exists? 'public'
179
+ 'public'
180
+ else
181
+ raise 'Please, run it from `Rails.root` or pass `-o` option'
182
+ end
183
+ end
184
+
183
185
  def url_base_path
184
186
  options[:url_base_path].presence.try(:strip).try(:sub, /^\/+/, '') || Lurker::DEFAULT_URL_BASE
185
187
  end
186
188
 
189
+ def assets
190
+ @assets ||= {}
191
+ end
192
+
193
+ def assets_root
194
+ Lurker::Cli.assets_root
195
+ end
196
+
197
+ def templates_root
198
+ Lurker::Cli.templates_root
199
+ end
200
+
201
+ def asset_logical_path(path)
202
+ path = Pathname.new(path) unless path.is_a? Pathname
203
+ path.sub %r{-[0-9a-f]{40}\.}, '.'
204
+ end
205
+
206
+ def asset_digest_path(path)
207
+ path = Pathname.new(path) unless path.is_a? Pathname
208
+ asset_logical_path(path).sub(/\.(\w+)$/) { |ext| "-#{hexdigest(path)}#{ext}" }
209
+ end
210
+
211
+ def hexdigest(path)
212
+ Digest::SHA1.hexdigest(open(path).read)
213
+ end
214
+
215
+ def path_extnames(path)
216
+ File.basename(path).scan(/\.[^.]+/)
217
+ end
218
+
219
+ def footer
220
+ `git rev-parse --short HEAD`.to_s.strip
221
+ rescue
222
+ ''
223
+ end
224
+
187
225
  def gem_info
188
226
  spec = if Bundler.respond_to? :locked_gems
189
- Bundler.locked_gems.specs.select { |s| s.name == 'lurker' } .first # 1.6
190
- else
191
- Bundler.definition.sources.detect { |s| s.specs.map(&:name).include?('lurker') } # 1.3
192
- end
227
+ Bundler.locked_gems.specs.select { |s| s.name == 'lurker' }.first # 1.6
228
+ else
229
+ Bundler.definition.sources.detect { |s| s.specs.map(&:name).include?('lurker') } # 1.3
230
+ end
193
231
 
194
232
  if spec.source.respond_to? :revision, true # bundler 1.3 private
195
233
  "#{spec.name} (#{spec.source.send(:revision)})"
@@ -198,26 +236,7 @@ module Lurker
198
236
  end
199
237
  rescue => e
200
238
  puts e
201
- "lurker (unknown)"
202
- end
203
-
204
- def get_content(content_fname)
205
- return unless content_fname
206
- content_fname = File.expand_path(content_fname)
207
- if content_fname.ends_with? 'md'
208
- Lurker.safe_require('kramdown')
209
- Kramdown::Document.new(open(content_fname).read).to_html
210
- else
211
- ''
212
- end
213
- end
214
-
215
- def services
216
- @services ||= [Lurker::Service.new(origin_path)]
217
- end
218
-
219
- def origin
220
- Pathname.new(origin_path)
239
+ 'lurker (unknown)'
221
240
  end
222
241
  end
223
242
  end
@@ -19,7 +19,7 @@ module Lurker
19
19
  RESPONSE_CODES = 'responseCodes'.freeze
20
20
  REQUEST_PARAMETERS = 'requestParameters'.freeze
21
21
  RESPONSE_PARAMETERS = 'responseParameters'.freeze
22
- DESCRPTIONS = {
22
+ DESCRIPTIONS = {
23
23
  'index' => 'listing',
24
24
  'show' => '',
25
25
  'edit' => 'editing',
@@ -44,7 +44,7 @@ module Lurker
44
44
  finalize_schema!
45
45
 
46
46
  Lurker::Json::Orderer.reorder(schema) unless persisted?
47
- Lurker::Json::Writter.write(schema, endpoint_path)
47
+ Lurker::Json::Writer.write(schema, endpoint_path)
48
48
 
49
49
  @persisted = true
50
50
  end
@@ -131,6 +131,10 @@ module Lurker
131
131
  @schema[RESPONSE_CODES]
132
132
  end
133
133
 
134
+ def documentation
135
+ @schema.documentation
136
+ end
137
+
134
138
  protected
135
139
 
136
140
  def persisted?
@@ -167,7 +171,7 @@ module Lurker
167
171
  def finalize_schema!
168
172
  path_params = schema[EXTENSIONS][PATH_PARAMS] || {}
169
173
  subject = path_params[CONTROLLER].to_s.split(/\//).last.to_s
170
- description = DESCRPTIONS[path_params[ACTION]]
174
+ description = DESCRIPTIONS[path_params[ACTION]]
171
175
 
172
176
  schema[DESCRIPTION] = "#{subject.singularize} #{description}".strip if schema[DESCRIPTION].blank?
173
177
  schema[PREFIX] = "#{subject} management" if schema[PREFIX].blank?