lurker 0.6.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +4 -78
  3. data/.jshintrc +33 -0
  4. data/.rspec +1 -2
  5. data/.rubocop.yml +0 -1
  6. data/.travis.yml +30 -19
  7. data/Gemfile +0 -33
  8. data/README.md +32 -53
  9. data/Rakefile +3 -3
  10. data/cucumber.yml +1 -2
  11. data/features/atom_persistent_within_the_same_type.feature +4 -4
  12. data/features/controller_nested_schema_scaffolding.feature +7 -10
  13. data/features/controller_schema_scaffolding.feature +1 -3
  14. data/features/dereferencing_through_inlining.feature +1 -3
  15. data/features/html_generation.feature +26 -4
  16. data/features/minitest.feature +3 -8
  17. data/features/multidomain_support.feature +6 -10
  18. data/features/multitype_request_support.feature +1 -3
  19. data/features/partials.feature +3 -8
  20. data/features/request_nested_schema_scaffolding.feature +0 -2
  21. data/features/request_schema_scaffolding.feature +0 -2
  22. data/features/schema_suffixes.feature +2 -18
  23. data/features/schema_updating_within_test_suite.feature +2 -6
  24. data/features/step_definitions/additional_cli_steps.rb +16 -12
  25. data/features/support/env.rb +50 -10
  26. data/features/test_endpoint.feature +2 -9
  27. data/gemfiles/rails_4.gemfile +14 -0
  28. data/gemfiles/rails_5.gemfile +10 -0
  29. data/gemfiles/rails_6.gemfile +10 -0
  30. data/lib/lurker.rb +9 -2
  31. data/lib/lurker/cli.rb +148 -128
  32. data/lib/lurker/endpoint.rb +11 -7
  33. data/lib/lurker/form_builder.rb +22 -31
  34. data/lib/lurker/json/concerns/validatable.rb +5 -1
  35. data/lib/lurker/json/parser.rb +1 -1
  36. data/lib/lurker/json/schema.rb +19 -6
  37. data/lib/lurker/json/{writter.rb → writer.rb} +2 -2
  38. data/lib/lurker/presenters/base_presenter.rb +10 -34
  39. data/lib/lurker/presenters/endpoint_presenter.rb +19 -8
  40. data/lib/lurker/presenters/schema_presenter.rb +6 -5
  41. data/lib/lurker/presenters/service_presenter.rb +41 -7
  42. data/lib/lurker/rendering_controller.rb +14 -7
  43. data/lib/lurker/service.rb +27 -11
  44. data/lib/lurker/spec_helper/rspec.rb +0 -4
  45. data/lib/lurker/spy.rb +3 -1
  46. data/lib/lurker/templates/documentation.md.tt +1 -0
  47. data/lib/lurker/templates/javascripts/lurker.js +133 -91
  48. data/lib/lurker/templates/layouts/_sidemenu.html.erb +2 -2
  49. data/lib/lurker/templates/layouts/application.html.erb +54 -57
  50. data/lib/lurker/templates/layouts/print.html.erb +31 -0
  51. data/lib/lurker/templates/lurker/rendering/_endpoint.html.erb +37 -0
  52. data/lib/lurker/templates/lurker/rendering/_param_form_element.html.erb +1 -1
  53. data/lib/lurker/templates/lurker/rendering/_service.html.erb +7 -0
  54. data/lib/lurker/templates/lurker/rendering/_submit_form.html.erb +77 -73
  55. data/lib/lurker/templates/lurker/rendering/all.html.erb +5 -0
  56. data/lib/lurker/templates/lurker/rendering/index.html.erb +1 -10
  57. data/lib/lurker/templates/lurker/rendering/show.html.erb +1 -37
  58. data/lib/lurker/templates/public/application.css +6 -2
  59. data/lib/lurker/templates/public/application.js +13 -13
  60. data/lib/lurker/templates/stylesheets/application.scss +3 -0
  61. data/lib/lurker/version.rb +1 -1
  62. data/lurker.gemspec +31 -33
  63. data/spec/spec_helper.rb +0 -1
  64. data/tasks/build.rake +12 -8
  65. data/tasks/generate.rake +44 -17
  66. data/templates/Dockerfile +26 -0
  67. data/templates/generate_stuff.rb +59 -26
  68. data/templates/lurker_app.rb +27 -48
  69. data/templates/rails4_ruby26_thread_error_fix.rb +20 -0
  70. metadata +149 -106
  71. checksums.yaml.gz.sig +0 -2
  72. data.tar.gz.sig +0 -3
  73. data/Appraisals +0 -20
  74. data/gemfiles/rails_32.gemfile +0 -27
  75. data/gemfiles/rails_40.gemfile +0 -27
  76. data/gemfiles/rails_41.gemfile +0 -27
  77. data/gemfiles/rails_42.gemfile +0 -27
  78. data/lib/lurker/templates/lurker/rendering/_param_form_legend.html.erb +0 -1
  79. data/lib/lurker/templates/meta_service.md.erb +0 -20
  80. data/lib/lurker/validation_error.rb +0 -4
  81. data/templates/rails32_http_patch_support.rb +0 -125
  82. metadata.gz.sig +0 -0
@@ -6,11 +6,19 @@ SimpleCov.start do
6
6
  end
7
7
  end
8
8
 
9
+ def relative_example_path
10
+ if rails_version = ENV['BUNDLE_GEMFILE'].to_s.match(/rails_\d+/)
11
+ "tmp/lurker_app_#{rails_version}"
12
+ else
13
+ raise "Export BUNDLE_GEMFILE=gemfiles/rails... explicitly"
14
+ end
15
+ end
16
+
9
17
  def example_path
10
- if rails_version = ENV['BUNDLE_GEMFILE'].to_s.match(/rails_\d\d/)
18
+ if rails_version = ENV['BUNDLE_GEMFILE'].to_s.match(/rails_\d+/)
11
19
  File.expand_path("../../../tmp/lurker_app_#{rails_version}", __FILE__)
12
20
  else
13
- raise "Use `appraisal rails-XY cucumber ...` or export BUNDLE_GEMFILE=gemfiles/... explicitly"
21
+ raise "Export BUNDLE_GEMFILE=gemfiles/rails... explicitly"
14
22
  end
15
23
  end
16
24
 
@@ -23,21 +31,53 @@ World(RSpec::Matchers)
23
31
  require 'capybara'
24
32
  require 'capybara/dsl'
25
33
  require 'capybara/cucumber'
26
- require 'capybara/poltergeist'
34
+ require 'webdrivers/chromedriver'
27
35
  require "#{example_path}/config/environment"
28
36
  require 'database_cleaner'
29
37
  require 'database_cleaner/cucumber'
30
38
 
31
- Capybara.app = Rails.application
32
- Capybara.javascript_driver = :poltergeist
39
+ Capybara.register_driver :chrome do |app|
40
+ Capybara::Selenium::Driver.new(app, browser: :chrome)
41
+ end
33
42
 
43
+ Capybara.register_driver :headless_chrome do |app|
44
+ Selenium::WebDriver.logger.level = :debug if ENV['CAPYBARA_DEBUG'].present?
45
+ browser_capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(loggingPrefs: { browser: 'ALL' })
46
+ browser_options = Selenium::WebDriver::Chrome::Options.new(args: %w[headless disable-gpu no-sandbox disable-dev-shm-usage window-size=1900,1080])
47
+ browser_options.add_argument('--ignore-certificate-errors')
48
+ # Disable w3c mode (default as of Chrome 75) to allow for logging
49
+ browser_options.add_option(:w3c, false)
50
+ Capybara::Selenium::Driver.new app,
51
+ browser: :chrome,
52
+ options: browser_options,
53
+ desired_capabilities: browser_capabilities
54
+ end
55
+
56
+ Capybara.app = Rails.application
57
+ Capybara.server = :puma, { Silent: true, Threads: '1:1' }
58
+ Capybara.javascript_driver = ENV['CAPYBARA_JS_DRIVER']&.to_sym || :headless_chrome
34
59
  DatabaseCleaner.strategy = :truncation
35
60
 
61
+ # otherwise it cleans up all rails folder
62
+ # https://github.com/cucumber/aruba/blob/bf612766ac51e28ca354e735980cd8a5d7eb296f/lib/aruba/setup.rb#L27L31
63
+ # it force deletes the working_directory,
64
+ # but it has to be working_directory to cd in and run `bin/rspec`
65
+ # this forces @no-clobber everywhere
66
+ # use CLEAN=1 env var to clean proper places
67
+ module ArubaSetupNoClobber
68
+ def working_directory(clobber = true)
69
+ super(false)
70
+ end
71
+ end
72
+ Aruba::Setup.prepend(ArubaSetupNoClobber)
73
+
36
74
  # see: https://github.com/colszowka/simplecov/issues/234
37
75
  Aruba.configure do |config|
38
- config.before_cmd do |cmd|
39
- set_env 'SIMPLECOV_CMDNAME', Digest::MD5.hexdigest(cmd)
40
- set_env 'SIMPLECOV_ROOT', File.expand_path('../../..', __FILE__)
76
+ config.working_directory = relative_example_path # Aruba::Contracts::RelativePath
77
+ config.activate_announcer_on_command_failure = [:stdout]
78
+ config.before :command do |cmd|
79
+ set_environment_variable 'SIMPLECOV_CMDNAME', Digest::MD5.hexdigest(cmd.object_id.to_s)
80
+ set_environment_variable 'SIMPLECOV_ROOT', File.expand_path('../../..', __FILE__)
41
81
  end
42
82
  end
43
83
 
@@ -47,8 +87,8 @@ Before do
47
87
  DatabaseCleaner.start
48
88
  if ENV['CLEAN']
49
89
  system "bin/spring stop"
50
- %w[lurker html public/lurker spec/requests spec/controllers].each do |dir_name|
51
- in_current_dir { _rm_rf(dir_name) }
90
+ %w[lurker public/lurker spec/requests spec/controllers].each do |dir_name|
91
+ in_current_directory { remove(dir_name, force: true) }
52
92
  end
53
93
  end
54
94
  end
@@ -17,9 +17,6 @@ Feature: test endpoint
17
17
  description: 'user updating'
18
18
  requestParameters:
19
19
  properties:
20
- id:
21
- type: integer
22
- example: 1
23
20
  user:
24
21
  type: object
25
22
  properties:
@@ -56,8 +53,6 @@ Feature: test endpoint
56
53
  Scenario: json schema tests request and response using "users/update"
57
54
  Given a file named "spec/controllers/api/v1/users_controller_spec.rb" with:
58
55
  """ruby
59
- require "spec_helper"
60
-
61
56
  describe Api::V1::UsersController, :lurker do
62
57
  render_views
63
58
 
@@ -66,7 +61,7 @@ Feature: test endpoint
66
61
  end
67
62
 
68
63
  it "updates a user" do
69
- patch :update, id: user.id, user: { name: 'Bob' }
64
+ patch :update, params: { id: user.id, user: { name: 'Bob' } }
70
65
  expect(response).to be_success
71
66
  end
72
67
  end
@@ -78,8 +73,6 @@ Feature: test endpoint
78
73
  Scenario: json schema tests response parameters and tell what fails using "users/update"
79
74
  Given a file named "spec/controllers/api/v1/users_controller_blank_spec.rb" with:
80
75
  """ruby
81
- require "spec_helper"
82
-
83
76
  describe Api::V1::UsersController, :lurker do
84
77
  render_views
85
78
 
@@ -88,7 +81,7 @@ Feature: test endpoint
88
81
  end
89
82
 
90
83
  it "updates a user" do
91
- patch :update, id: user.id, user: { name: '' }, format: 'json'
84
+ patch :update, params: { id: user.id, user: { name: '' }, format: 'json' }
92
85
  expect(response).not_to be_success
93
86
  end
94
87
  end
@@ -0,0 +1,14 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 4.2"
4
+ gem "bigdecimal", "~> 1.4"
5
+ gem "pg", "<= 0.20" # doesnt use 1.0 by install, 0.21 too many warnings
6
+
7
+ gem "rails-forward_compatible_controller_tests", "> 0"
8
+
9
+ gem "jquery-rails"
10
+ gem "bootstrap-sass"
11
+ gem "remotipart"
12
+ gem "uglifier"
13
+
14
+ gemspec :path => "../"
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 5.2"
4
+
5
+ gem "jquery-rails"
6
+ gem "bootstrap-sass"
7
+ gem "remotipart"
8
+ gem "uglifier"
9
+
10
+ gemspec :path => "../"
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.0"
4
+
5
+ gem "jquery-rails"
6
+ gem "bootstrap-sass"
7
+ gem "remotipart"
8
+ gem "uglifier"
9
+
10
+ gemspec :path => "../"
@@ -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
@@ -52,7 +60,6 @@ require 'lurker/ref_object'
52
60
  require 'lurker/erb_schema_context'
53
61
  require 'lurker/service'
54
62
  require 'lurker/validator'
55
- require 'lurker/validation_error'
56
63
  require 'lurker/utils'
57
64
  require 'lurker/endpoint'
58
65
  require 'lurker/rendering_controller'
@@ -65,7 +72,7 @@ require 'lurker/presenters/schema_presenter'
65
72
  require 'lurker/presenters/response_code_presenter'
66
73
  require 'lurker/json'
67
74
  require 'lurker/json/reader'
68
- require 'lurker/json/writter'
75
+ require 'lurker/json/writer'
69
76
  require 'lurker/json/orderer'
70
77
  require 'lurker/json/parser'
71
78
  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,130 @@ 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
+ 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
+ print_html = service_presenter.to_print
84
+ create_file "#{service_presenter.url_name}_print.html", print_html, force: true
85
+
86
+ kit = PDFKit.new(print_html)
87
+ kit.stylesheets << assets['application.css']
88
+ create_file "#{service_presenter.url_name}.pdf", kit.to_pdf, force: true
75
89
  end
76
90
 
77
91
  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)
92
+ create_file 'index.html', service_presenter.to_html, force: true
95
93
 
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
102
-
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/, '')
94
+ service_presenter.endpoints.each do |endpoint_prefix_group|
95
+ endpoint_prefix_group.each do |endpoint_presenter|
96
+ create_file(endpoint_presenter.relative_path, endpoint_presenter.to_html, force: true)
112
97
  end
113
98
  end
114
99
  end
115
100
 
116
- def output_path
117
- "#{output_prefix}/#{url_base_path}"
101
+ def setup_schema_root!(path)
102
+ Lurker.service_path = File.expand_path(path)
103
+ raise Lurker::NotFound.new(Lurker.service_path) unless Lurker.valid_service_path?
104
+ say_status :using, path
118
105
  end
119
106
 
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"
107
+ def setup_rendering_engine!
108
+ I18n.config.enforce_available_locales = true
109
+ Lurker::RenderingController.prepend_view_path Lurker::Cli.templates_root
110
+ if options[:templates].present?
111
+ Lurker::RenderingController.prepend_view_path Pathname.new(options[:templates]).expand_path
127
112
  end
113
+ Lurker::RenderingController.config.assets_dir = assets_root
128
114
  end
129
115
 
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
116
+ def prepare_assets!
117
+ directory assets_root, '.', exclude_pattern: /application\.(js|css)$/
118
+ digest_asset!('application.js')
119
+ digest_asset!('application.css')
137
120
  end
138
121
 
139
- def has_valid_origin?
140
- origin.directory?
122
+ def cleanup_assets!
123
+ actual = assets.values
124
+ Dir.glob('*.{js,css,gz}').each do |fname|
125
+ remove_file fname unless actual.include? fname.sub(/\.gz/, '')
126
+ end
141
127
  end
142
128
 
143
- def service_presenters
144
- @service_presenters ||= services.map do |service|
145
- Lurker::ServicePresenter.new(service, html_options, &filtering_block)
129
+ def digest_asset!(name)
130
+ if (asset_path = assets_root + name).exist?
131
+ digest_path = asset_digest_path(asset_path).basename
132
+ assets[asset_path.basename.to_s] = digest_path.to_s
133
+ copy_file asset_path, digest_path, skip: true
134
+ spawn "cat #{digest_path} | gzip -9 > #{digest_path}.gz"
146
135
  end
147
136
  end
148
137
 
138
+ def service_presenter
139
+ @service_presenter ||= Lurker::ServicePresenter.new(Lurker.service, html_options, &filtering_block)
140
+ end
141
+
149
142
  def filtering_block
150
143
  if options['select'].present?
151
144
  select = /#{options['select']}/
@@ -167,29 +160,75 @@ module Lurker
167
160
 
168
161
  def html_options
169
162
  @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
163
+ static_html: true,
164
+ url_base_path: url_base_path.prepend('/'),
165
+ assets_directory: assets_root,
166
+ assets: assets,
167
+ html_directory: output_path,
168
+ footer: footer,
169
+ lurker: gem_info
177
170
  }
178
171
  end
179
172
  end
180
173
 
181
174
  private
182
175
 
176
+ def output_path
177
+ "#{output_prefix}/#{url_base_path}"
178
+ end
179
+
180
+ def output_prefix
181
+ if explicit = options[:output]
182
+ explicit.sub(/\/?#{url_base_path}\/?$/, '')
183
+ elsif File.exists? 'public'
184
+ 'public'
185
+ else
186
+ raise 'Please, run it from `Rails.root` or pass `-o` option'
187
+ end
188
+ end
189
+
183
190
  def url_base_path
184
191
  options[:url_base_path].presence.try(:strip).try(:sub, /^\/+/, '') || Lurker::DEFAULT_URL_BASE
185
192
  end
186
193
 
194
+ def assets
195
+ @assets ||= {}
196
+ end
197
+
198
+ def assets_root
199
+ Lurker::Cli.assets_root
200
+ end
201
+
202
+ def asset_logical_path(path)
203
+ path = Pathname.new(path) unless path.is_a? Pathname
204
+ path.sub %r{-[0-9a-f]{40}\.}, '.'
205
+ end
206
+
207
+ def asset_digest_path(path)
208
+ path = Pathname.new(path) unless path.is_a? Pathname
209
+ asset_logical_path(path).sub(/\.(\w+)$/) { |ext| "-#{hexdigest(path)}#{ext}" }
210
+ end
211
+
212
+ def hexdigest(path)
213
+ Digest::SHA1.hexdigest(open(path).read)
214
+ end
215
+
216
+ def path_extnames(path)
217
+ File.basename(path).scan(/\.[^.]+/)
218
+ end
219
+
220
+ def footer
221
+ `git rev-parse --short HEAD`.to_s.strip
222
+ rescue
223
+ ''
224
+ end
225
+
187
226
  def gem_info
188
227
  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
228
+ Bundler.locked_gems.specs.select { |s| s.name == 'lurker' }.first # 1.6
229
+ else
230
+ Bundler.definition.sources.detect { |s| s.specs.map(&:name).include?('lurker') } # 1.3
231
+ end
193
232
 
194
233
  if spec.source.respond_to? :revision, true # bundler 1.3 private
195
234
  "#{spec.name} (#{spec.source.send(:revision)})"
@@ -198,26 +237,7 @@ module Lurker
198
237
  end
199
238
  rescue => e
200
239
  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)
240
+ 'lurker (unknown)'
221
241
  end
222
242
  end
223
243
  end