lurker 0.6.8 → 1.0.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.
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
@@ -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?
@@ -188,15 +192,15 @@ module Lurker
188
192
  def word_wrap(text)
189
193
  # strip .json# | .json.yml# | .json.yml.erb#
190
194
  text = text.reverse
191
- text.gsub!(/(\n|^)#bre\./, "\nbre.")
192
- text.gsub!(/(\n|^)#lmy\./, "\nlmy.")
193
- text.gsub!(/(\n|^)#nosj\./, "\nnosj.")
195
+ text.gsub!(/(\n|^)#bre\./, "\nbre.") # erb
196
+ text.gsub!(/(\n|^)#lmy\./, "\nlmy.") # yml
197
+ text.gsub!(/(\n|^)#nosj\./, "\nnosj.") # json
194
198
  text.strip!
195
199
  text = text.reverse
196
200
 
197
201
  text.gsub!(/\s+in schema/m, "\n in schema")
198
202
  if defined?(Rails)
199
- text.gsub!(/file:\/\/#{Rails.root}\//m, "")
203
+ text.gsub!(Regexp.new("#{Rails.root}\/"), "")
200
204
  end
201
205
  text
202
206
  end
@@ -11,55 +11,46 @@ module Lurker
11
11
 
12
12
  private
13
13
 
14
- def add_to_buffer(params, parent_labels = [])
15
- params.each do |label, value|
16
- if parent_labels.present?
17
- label = "[#{label}]"
18
- end
19
-
20
- new_parent_labels = parent_labels.clone << label
14
+ def add_to_buffer(params, parent_accessors = [])
15
+ params.each do |name, value|
21
16
 
17
+ accessors = parent_accessors.clone << name
22
18
  if value.is_a?(Hash)
23
- add_legend_to_buffer(parent_labels, label)
24
-
25
- add_to_buffer(value, new_parent_labels)
19
+ add_to_buffer(value, accessors)
26
20
  elsif value.is_a?(Array)
27
- value.each do |v|
21
+ value.each_with_index do |v, i|
28
22
  if v.is_a?(Hash)
29
- add_legend_to_buffer(parent_labels, label)
30
-
31
- add_to_buffer(v, parent_labels.clone << "#{label}[]")
23
+ add_to_buffer(v, accessors << i)
32
24
  else
33
- add_element_to_buffer(parent_labels, "#{label}[]", v)
25
+ add_element_to_buffer(accessors, v)
34
26
  end
35
27
  end
36
28
  else
37
- add_element_to_buffer(parent_labels, label, value)
29
+ add_element_to_buffer(accessors, value)
38
30
  end
39
31
  end
40
32
  end
41
33
 
42
- def add_element_to_buffer(parent_labels, label, value)
34
+ def add_element_to_buffer(accessors, value)
43
35
  @_buffer += render(
44
36
  :partial => 'param_form_element',
45
- :locals => {
46
- :label => "#{print_labels(parent_labels)}#{label}",
47
- :label_text => "#{print_labels(parent_labels)}#{label}",
48
- :value => value
37
+ :locals => {
38
+ :accessor => "#{accessors.compact.join('.')}",
39
+ :label => "#{print_labels(accessors)}",
40
+ :label_text => "#{print_labels(accessors)}",
41
+ :value => value
49
42
  }
50
43
  )
51
44
  end
52
45
 
53
- def add_legend_to_buffer(parent_labels, label)
54
- return
55
- @_buffer += render(
56
- :partial => 'param_form_legend',
57
- :locals => { :label => print_labels(parent_labels.clone << label) }
58
- )
59
- end
60
-
61
- def print_labels(parent_labels)
62
- "#{parent_labels * ''}"
46
+ def print_labels(accessors)
47
+ accessors.inject do |acc, label|
48
+ if label.is_a? Numeric
49
+ "#{acc}[]"
50
+ else
51
+ "#{acc}[#{label}]"
52
+ end
53
+ end
63
54
  end
64
55
  end
65
56
  end
@@ -9,7 +9,11 @@ module Lurker
9
9
 
10
10
  def to_validation_schema
11
11
  set_additional_properties_false_on(to_hash).tap do |schema|
12
- schema[Json::ID] = "file://#{uri}"
12
+ if uri.class == URI::Generic
13
+ schema[Json::ID] = uri.path
14
+ else
15
+ schema[Json::ID] = uri.to_s
16
+ end
13
17
  end
14
18
  end
15
19
 
@@ -16,7 +16,7 @@ module Lurker
16
16
  @parent_schema = options[:parent_schema]
17
17
  @parent_property = options[:parent_property]
18
18
  @polymorph_if_empty = options.fetch(:polymorph_if_empty, false)
19
- @uri = options[:uri] || @parent_schema.try(:uri)
19
+ @uri = options[:uri] || @parent_schema&.uri
20
20
  @strategy = nil
21
21
  end
22
22
 
@@ -21,6 +21,16 @@ module Lurker
21
21
  parse_schema(schema)
22
22
  end
23
23
 
24
+ def documentation_uri(extension = 'md')
25
+ @uri.to_s.sub(%r{^file:(//)?}, '').sub(/(\.json)?(\.yml)?(\.erb)?$/, ".#{extension}")
26
+ end
27
+
28
+ def documentation
29
+ open(documentation_uri).read
30
+ rescue
31
+ @schema['description']
32
+ end
33
+
24
34
  def root?
25
35
  root_schema.blank?
26
36
  end
@@ -40,8 +50,7 @@ module Lurker
40
50
  end
41
51
 
42
52
  def replace!(property, property_schema)
43
- @schema[property] = Lurker::Json::Parser.plain(subschema_options)
44
- .parse_property(property, property_schema)
53
+ @schema[property] = @parser.plain.parse_property(property, property_schema)
45
54
  end
46
55
 
47
56
  def reorder!
@@ -54,19 +63,23 @@ module Lurker
54
63
  end
55
64
 
56
65
  def to_json(options = {})
57
- hashify(@schema, options).to_json
66
+ to_hash(options).to_json
58
67
  end
59
68
 
60
69
  def to_yaml(options = {})
61
70
  YAML.dump(to_hash(options))
62
71
  end
63
72
 
73
+ def respond_to_missing?(method, include_private=false)
74
+ @schema.respond_to?(method, include_private)
75
+ end
76
+
64
77
  def method_missing(method, *args, &block)
65
78
  if @schema.is_a?(Lurker::Json::Schema) || @schema.respond_to?(method)
66
- return @schema.send(method, *args, &block)
79
+ @schema.send(method, *args, &block)
80
+ else
81
+ super
67
82
  end
68
-
69
- super
70
83
  end
71
84
 
72
85
  private
@@ -1,6 +1,6 @@
1
1
  module Lurker
2
2
  module Json
3
- class Writter
3
+ class Writer
4
4
  class << self
5
5
  def write(schema, path)
6
6
  new(path).write(schema)
@@ -16,7 +16,7 @@ module Lurker
16
16
  write_to_file(schema)
17
17
 
18
18
  extract_references(schema).each do |reference|
19
- Lurker::Json::Writter.write(reference, reference.original_uri.path)
19
+ Lurker::Json::Writer.write(reference, reference.original_uri.path)
20
20
  end
21
21
  end
22
22
 
@@ -9,16 +9,6 @@ class Lurker::BasePresenter
9
9
  @options = options
10
10
  end
11
11
 
12
- def render_erb(erb_name, binding = get_binding)
13
- template_path = path_for_template(erb_name)
14
- template = ERB.new(File.read(template_path), nil, '-')
15
- template.result(binding)
16
- end
17
-
18
- def get_binding
19
- binding
20
- end
21
-
22
12
  def html_directory
23
13
  options[:url_base_path] || options[:html_directory] || ""
24
14
  end
@@ -27,8 +17,12 @@ class Lurker::BasePresenter
27
17
  options[:url_base_path] || '/'
28
18
  end
29
19
 
30
- def css_path
31
- File.join(html_directory, "styles.css")
20
+ def assets
21
+ options[:assets] || {}
22
+ end
23
+
24
+ def asset_path(asset)
25
+ "#{html_directory}/#{assets[asset] || asset}"
32
26
  end
33
27
 
34
28
  def index_path(subdirectory = "")
@@ -51,27 +45,9 @@ class Lurker::BasePresenter
51
45
  EOS
52
46
  end
53
47
 
54
- def render(*args)
55
- rendering_controller.render_to_string(*args)
56
- end
57
-
58
- protected
59
-
60
- def path_for_template(filename)
61
- template_dir = options[:template_directory]
62
- template_path = File.join(template_dir, filename) if template_dir
63
- if template_path.nil? || !File.exist?(template_path)
64
- template_path = File.join(File.dirname(__FILE__), "../templates", filename)
65
- end
66
- template_path
67
- end
68
-
69
- def rendering_controller
70
- return @rendering_controller if @rendering_controller
71
- @rendering_controller = Lurker::RenderingController.new
72
- instance_variables.each do |var|
73
- @rendering_controller.instance_variable_set(var, instance_variable_get(var))
74
- end
75
- @rendering_controller
48
+ def markup(content)
49
+ return unless content
50
+ Lurker.safe_require 'kramdown'
51
+ defined?(Kramdown) ? Kramdown::Document.new(content).to_html : content
76
52
  end
77
53
  end
@@ -2,6 +2,9 @@
2
2
  class Lurker::EndpointPresenter < Lurker::BasePresenter
3
3
  attr_accessor :service_presenter, :endpoint, :endpoint_presenter
4
4
 
5
+ extend Forwardable
6
+ def_delegators :endpoint, :url_params
7
+
5
8
  def initialize(endpoint, options = {})
6
9
  super(options)
7
10
  @endpoint = endpoint
@@ -10,11 +13,15 @@ class Lurker::EndpointPresenter < Lurker::BasePresenter
10
13
  end
11
14
 
12
15
  def to_html(options={})
13
- @service_presenter = service_presenter
14
- @endpoint_presenter = self
15
- @url_params = endpoint.url_params
16
- @post_params = example_request.json
17
- render('show', options)
16
+ controller = Lurker::RenderingController.new
17
+ controller.service_presenter = service_presenter
18
+ controller.endpoint_presenter = self
19
+ controller.instance_variable_set :@title, "#{service_presenter.title} | #{title}"
20
+ controller.render_to_string 'show', options
21
+ end
22
+
23
+ def documentation
24
+ markup @endpoint.documentation
18
25
  end
19
26
 
20
27
  def relative_path(extension = ".html")
@@ -33,6 +40,10 @@ class Lurker::EndpointPresenter < Lurker::BasePresenter
33
40
  endpoint.prefix || endpoint.path.split("/").first
34
41
  end
35
42
 
43
+ def post_params
44
+ example_request.json
45
+ end
46
+
36
47
  def zws_ify(str)
37
48
  # zero-width-space, makes long lines friendlier for breaking
38
49
  # str.gsub(/\//, '&#8203;/') if str
@@ -209,15 +220,15 @@ class Lurker::EndpointPresenter < Lurker::BasePresenter
209
220
  end
210
221
 
211
222
  def example_from_array(array, parent=nil)
212
- if array["items"].is_a? Array
223
+ if array["items"].respond_to?(:each) && !array["items"].respond_to?(:each_pair)
213
224
  example = []
214
225
  array["items"].each do |item|
215
226
  example << example_from_schema(item, parent)
216
227
  end
217
228
  example
218
- elsif (array["items"] || {})["type"].is_a? Array
229
+ elsif (types = (array["items"] || {})["type"]).respond_to?(:each)
219
230
  example = []
220
- array["items"]["type"].each do |item|
231
+ types.each do |item|
221
232
  example << example_from_schema(item, parent)
222
233
  end
223
234
  example
@@ -116,18 +116,19 @@ class Lurker::SchemaPresenter < Lurker::BasePresenter
116
116
 
117
117
  def items_html
118
118
  return unless items = @schema["items"]
119
+ return if items.size == 0
119
120
 
120
121
  html = ""
121
122
  html << '<li>Items'
122
123
 
123
124
  sub_options = options.merge(:nested => options[:nested] + 1, :parent => self)
124
125
 
125
- if items.is_a? Array
126
- item.compact.each do |item|
127
- html << self.class.new(item, sub_options).to_html
128
- end
129
- else
126
+ if items.respond_to?(:each_pair)
130
127
  html << self.class.new(items, sub_options).to_html
128
+ else
129
+ items.each do |item|
130
+ html << self.class.new(item, sub_options).to_html if item
131
+ end
131
132
  end
132
133
 
133
134
  html << '</li>'
@@ -1,3 +1,6 @@
1
+ require 'active_support/inflector'
2
+ require 'active_support/hash_with_indifferent_access'
3
+
1
4
  # An BasePresenter for Lurker::Service
2
5
  class Lurker::ServicePresenter < Lurker::BasePresenter
3
6
  attr_reader :service
@@ -11,14 +14,24 @@ class Lurker::ServicePresenter < Lurker::BasePresenter
11
14
  @filtering_block = block
12
15
  end
13
16
 
14
- # TODO move to controller
15
- def to_html(&block)
16
- @service_presenter = self
17
- render('index')
17
+ def to_html(options={}, &block)
18
+ controller = Lurker::RenderingController.new
19
+ controller.service_presenter = self
20
+ controller.render_to_string 'index', options
21
+ end
22
+
23
+ def to_print(options = {})
24
+ controller = Lurker::RenderingController.new
25
+ controller.service_presenter = self
26
+ controller.render_to_string 'all', { layout: 'print' }.merge(options)
27
+ end
28
+
29
+ def documentation
30
+ markup @service.documentation
18
31
  end
19
32
 
20
33
  def title
21
- "Lurker | #{name}"
34
+ "#{name}"
22
35
  end
23
36
 
24
37
  def domains
@@ -31,19 +44,40 @@ class Lurker::ServicePresenter < Lurker::BasePresenter
31
44
  '/'
32
45
  end
33
46
 
47
+ def request_media_types
48
+ return service.request_media_types if service.request_media_types.present?
49
+ ['application/x-www-form-urlencoded']
50
+ end
51
+
52
+ def default_request_media_type
53
+ request_media_types[0]
54
+ end
55
+
34
56
  def name_as_link(options = {})
35
57
  path = index_path
36
58
  '<a href="%s">%s %s</a>' % [path, options[:prefix], service.name]
37
59
  end
38
60
 
39
61
  def slug_name
40
- service.name.downcase.gsub(/[ \/]/, '_')
62
+ @slug_name ||= service.name.downcase.gsub(/[ \/]/, '_')
63
+ end
64
+
65
+ def url_name
66
+ @url_name ||= name.gsub(/[^a-z0-9\-_]+/i, '_')
41
67
  end
42
68
 
43
69
  def url(extension = ".html")
44
70
  '%s-%s%s' % [@endpoint.path, @endpoint.verb, extension]
45
71
  end
46
72
 
73
+ def footer
74
+ @footer ||= options[:footer].present? ? "Revision&nbsp;#{options[:footer]}".html_safe : ''
75
+ end
76
+
77
+ def lurker
78
+ @lurker ||= options[:lurker] || ''
79
+ end
80
+
47
81
  def endpoints
48
82
  unless @endpoints
49
83
  @endpoints = []
@@ -91,6 +125,6 @@ class Lurker::ServicePresenter < Lurker::BasePresenter
91
125
  private
92
126
 
93
127
  def service_domains
94
- service.domains.to_hash
128
+ service.domains.try(:to_hash) || {}
95
129
  end
96
130
  end