lurker 0.6.2 → 0.6.3

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 (48) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -1
  3. data/Gemfile +1 -0
  4. data/features/dereferencing_through_inlining.feature +102 -0
  5. data/features/partials.feature +3 -1
  6. data/features/step_definitions/additional_cli_steps.rb +19 -0
  7. data/features/support/files_helper.rb +7 -0
  8. data/lib/lurker/endpoint.rb +85 -50
  9. data/lib/lurker/json/concerns/validatable.rb +47 -0
  10. data/lib/lurker/json/orderer.rb +19 -0
  11. data/lib/lurker/json/parser/expertise.rb +30 -0
  12. data/lib/lurker/json/parser/plain_strategy.rb +39 -0
  13. data/lib/lurker/json/parser/typed_strategy.rb +71 -0
  14. data/lib/lurker/json/parser.rb +73 -0
  15. data/lib/lurker/json/reader.rb +28 -0
  16. data/lib/lurker/json/schema/attribute.rb +115 -0
  17. data/lib/lurker/json/schema/extensions.rb +19 -0
  18. data/lib/lurker/json/schema/list.rb +51 -0
  19. data/lib/lurker/json/schema/object.rb +67 -0
  20. data/lib/lurker/json/schema/reference.rb +34 -0
  21. data/lib/lurker/{endpoint → json/schema}/response_codes.rb +13 -16
  22. data/lib/lurker/json/schema/tuple/all_of.rb +17 -0
  23. data/lib/lurker/json/schema/tuple/any_of.rb +17 -0
  24. data/lib/lurker/json/schema/tuple/one_of.rb +17 -0
  25. data/lib/lurker/json/schema/tuple.rb +38 -0
  26. data/lib/lurker/json/schema.rb +122 -0
  27. data/lib/lurker/json/writter.rb +58 -0
  28. data/lib/lurker/presenters/endpoint_presenter.rb +2 -2
  29. data/lib/lurker/presenters/schema_presenter.rb +4 -1
  30. data/lib/lurker/presenters/service_presenter.rb +8 -2
  31. data/lib/lurker/service.rb +4 -4
  32. data/lib/lurker/version.rb +1 -1
  33. data/lib/lurker.rb +19 -8
  34. data/spec/lurker/json/list_spec.rb +101 -0
  35. data/spec/lurker/json/schema_spec.rb +126 -0
  36. data/spec/spec_helper.rb +2 -0
  37. data/spec/support/matchers/json_attribute.rb +27 -0
  38. data/spec/support/matchers/json_object.rb +33 -0
  39. data/templates/generate_stuff.rb +19 -10
  40. data.tar.gz.sig +2 -4
  41. metadata +33 -9
  42. metadata.gz.sig +0 -0
  43. data/lib/lurker/endpoint/http_parameters.rb +0 -77
  44. data/lib/lurker/schema.rb +0 -89
  45. data/lib/lurker/schema_modifier/array.rb +0 -28
  46. data/lib/lurker/schema_modifier/atom.rb +0 -97
  47. data/lib/lurker/schema_modifier/hash.rb +0 -30
  48. data/lib/lurker/schema_modifier.rb +0 -48
@@ -0,0 +1,28 @@
1
+ module Lurker
2
+ module Json
3
+ class Reader
4
+ attr_reader :path
5
+
6
+ def initialize(path)
7
+ @path = path
8
+ @attempts_left = 1
9
+ end
10
+
11
+ def read
12
+ return YAML.load_file(@path) unless @path.match(/\.erb$/)
13
+
14
+ context = Lurker::ErbSchemaContext.new
15
+ erb = ERB.new(IO.read @path).result(context.get_binding)
16
+ YAML.load(erb)
17
+ rescue Errno::ENOENT
18
+ raise if @attempts_left.zero?
19
+
20
+ @path = @path.sub(/\#\/?$/, '').sub(/\.json/, '.json.yml')
21
+ @attempts_left -= 1
22
+
23
+ retry
24
+ end
25
+ alias_method :payload, :read
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,115 @@
1
+ require 'action_dispatch'
2
+
3
+ module Lurker
4
+ module Json
5
+ class Attribute < Schema
6
+ URI = 'uri'.freeze
7
+ TYPE = 'type'.freeze
8
+ COLOR = 'color'.freeze
9
+ FORMAT = 'format'.freeze
10
+ EXAMPLE = 'example'.freeze
11
+ DATE_TIME = 'date-time'.freeze
12
+ DESCRIPTION = 'description'.freeze
13
+
14
+ TYPE_MAP = {
15
+ 'Time' => 'string',
16
+ 'Hash' => 'object',
17
+ 'Float' => 'number',
18
+ 'Fixnum' => 'integer',
19
+ 'NilClass' => 'null',
20
+ 'TrueClass' => 'boolean',
21
+ 'FalseClass' => 'boolean',
22
+ 'ActionDispatch::Http::UploadedFile' => 'string'
23
+ }.freeze
24
+
25
+ def merge!(schema)
26
+ return replace!(schema) if @schema[TYPE].blank?
27
+
28
+ schema = attributify(schema)
29
+ return if eql?(schema)
30
+
31
+ replace_options = {root_schema: root_schema, parent_schema: parent_schema,
32
+ parent_property: parent_property}
33
+
34
+ attributes_tuple = Lurker::Json::Tuple::AnyOf.new(
35
+ [to_hash, schema], replace_options)
36
+
37
+ parent_schema.replace!(parent_property, attributes_tuple)
38
+ end
39
+
40
+ def replace!(schema)
41
+ @schema.clear.merge!(attributify schema)
42
+ end
43
+
44
+ def eql?(schema)
45
+ @schema[TYPE] == attributify(schema)[TYPE]
46
+ end
47
+
48
+ private
49
+
50
+ def parse_schema(schema)
51
+ @schema = {}
52
+ initialize_properties
53
+
54
+ if schema.is_a?(Hash)
55
+ @schema.merge!(schema)
56
+ else
57
+ @schema = attributify(schema)
58
+ end
59
+ end
60
+
61
+ def attributify(schema)
62
+ return schema if schema.is_a?(Hash) || schema.is_a?(Lurker::Json::Schema)
63
+
64
+ attribute = {
65
+ DESCRIPTION => '',
66
+ TYPE => guess_type(schema),
67
+ EXAMPLE => serialize_example(schema)
68
+ }
69
+
70
+ if format = guess_format(schema)
71
+ attribute[FORMAT] = format
72
+ end
73
+
74
+ attribute
75
+ end
76
+
77
+ def initialize_properties
78
+ @schema[DESCRIPTION] ||= ''
79
+ @schema[TYPE] ||= ''
80
+ @schema[EXAMPLE] ||= ''
81
+ end
82
+
83
+ def serialize_example(data)
84
+ if data.is_a?(ActionDispatch::Http::UploadedFile)
85
+ data.headers
86
+ else
87
+ data
88
+ end
89
+ end
90
+
91
+ def guess_type(data)
92
+ data_type = data.class.to_s
93
+ TYPE_MAP[data_type] || data_type.downcase
94
+ end
95
+
96
+ def guess_format(data)
97
+ if data.is_a?(Time)
98
+ DATE_TIME
99
+ elsif data.is_a?(String)
100
+ if data.start_with? 'http://'
101
+ URI
102
+ elsif data.match(/\#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?\b/)
103
+ COLOR
104
+ else
105
+ begin
106
+ DATE_TIME if Time.iso8601(data)
107
+ rescue
108
+ nil
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,19 @@
1
+ module Lurker
2
+ module Json
3
+ class Extensions < Schema
4
+ EXTENSIONS = 'extensions'.freeze
5
+
6
+ def initialize(schema, options = {})
7
+ @parent_property = EXTENSIONS
8
+
9
+ super
10
+ end
11
+
12
+ def merge!(schema)
13
+ return unless Lurker.upgrade?
14
+
15
+ @schema = @parser.parse_property(parent_property, schema)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,51 @@
1
+ module Lurker
2
+ module Json
3
+ class List < Schema
4
+ TYPE = 'type'.freeze
5
+ ARRAY = 'array'.freeze
6
+ ITEMS = 'items'.freeze
7
+
8
+ def merge!(schema)
9
+ if schema.is_a?(Array)
10
+ schema.each { |payload| @schema[ITEMS].merge!(payload) }
11
+ else
12
+ @schema[ITEMS].merge!(schema)
13
+ end
14
+ end
15
+
16
+ def replace!(property, schema)
17
+ if @schema[ITEMS].is_a?(Lurker::Json::Attribute)
18
+ @schema[ITEMS] = schema
19
+ else
20
+ @schema[ITEMS].replace!(property, schema)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def parse_schema(schema)
27
+ @schema = {}
28
+ initialize_properties
29
+
30
+ return if schema.empty?
31
+
32
+ schema = schema.dup
33
+ if schema.is_a?(Array)
34
+ @schema[ITEMS] = @parser.typed.parse(schema.shift)
35
+
36
+ schema.each { |payload| @schema[ITEMS].merge!(payload) }
37
+ else
38
+ @schema[ITEMS] = @parser.typed.parse(schema.delete ITEMS) if schema.key?(ITEMS)
39
+ @schema.merge!(schema)
40
+ end
41
+
42
+ @schema
43
+ end
44
+
45
+ def initialize_properties
46
+ @schema[TYPE] ||= ARRAY
47
+ @schema[ITEMS] ||= []
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,67 @@
1
+ module Lurker
2
+ module Json
3
+ class Object < Schema
4
+ TYPE = 'type'.freeze
5
+ OBJECT = 'object'.freeze
6
+ REQUIRED = 'required'.freeze
7
+ PROPERTIES = 'properties'.freeze
8
+ DESCRIPTION = 'description'.freeze
9
+ ADDITIONAL_PROPERTIES = 'additionalProperties'.freeze
10
+
11
+ def merge!(schema)
12
+ unless schema.is_a?(Hash)
13
+ return replace_with_new_type(schema) if @schema[PROPERTIES].blank?
14
+
15
+ raise TypeError, "Unable to merge #{schema.class} into JSON object"
16
+ end
17
+
18
+ schema.each do |property, property_schema|
19
+ if @schema[PROPERTIES].key?(property)
20
+ @schema[PROPERTIES][property].merge!(property_schema)
21
+ next
22
+ end
23
+
24
+ replace!(property, property_schema)
25
+ end
26
+ end
27
+
28
+ def replace!(property, property_schema)
29
+ @schema[PROPERTIES][property] = Lurker::Json::Parser.typed(subschema_options)
30
+ .parse_property(property, property_schema)
31
+ end
32
+
33
+ private
34
+
35
+ def parse_schema(schema)
36
+ @schema = {}
37
+ initialize_properties
38
+
39
+ schema = schema.dup
40
+ merge_required = schema.key?(PROPERTIES)
41
+
42
+ (schema.delete(PROPERTIES) || schema).each do |property, property_schema|
43
+ @schema[PROPERTIES][property] = @parser.typed.parse_property(
44
+ property, property_schema)
45
+ end
46
+
47
+ @schema.merge!(schema) if merge_required
48
+ end
49
+
50
+ def replace_with_new_type(schema)
51
+ replace_options = {root_schema: root_schema, parent_schema: parent_schema,
52
+ parent_property: parent_property}
53
+
54
+ new_schema = Lurker::Json::Parser.typed(replace_options).parse(schema)
55
+ parent_schema.replace!(parent_property, new_schema)
56
+ end
57
+
58
+ def initialize_properties
59
+ @schema[DESCRIPTION] ||= ''
60
+ @schema[TYPE] ||= OBJECT
61
+ @schema[ADDITIONAL_PROPERTIES] = !!@schema[ADDITIONAL_PROPERTIES]
62
+ @schema[REQUIRED] ||= []
63
+ @schema[PROPERTIES] ||= {}
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,34 @@
1
+ module Lurker
2
+ module Json
3
+ class Reference < Schema
4
+ REF = '$ref'.freeze
5
+
6
+ attr_reader :original_uri
7
+
8
+ delegate :merge!, :replace!, :reorder!, to: :@schema
9
+
10
+ def to_original_hash(options = {})
11
+ @original_schema.to_hash
12
+ end
13
+
14
+ private
15
+
16
+ def parse_schema(schema)
17
+ @original_schema = schema.dup
18
+
19
+ # NOTE : We decide that reference is relative, so we are using merge
20
+ # We use first read for correct relative path resolving
21
+ reader = Lurker::Json::Reader.new(@uri.merge(schema[REF]).path)
22
+ payload = reader.payload
23
+
24
+ @original_uri = parse_uri(reader.path)
25
+ @schema = @parser.plain(uri: reader.path).parse(payload)
26
+
27
+ # NOTE : The easiest way to get schema copy is to parse it again.
28
+ # It's faster and reliable
29
+ # @_schema = @parser.plain(uri: reader.path).parse(reader.payload)
30
+ # @_schema_file = URI.parse(reader.path)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,24 +1,21 @@
1
1
  module Lurker
2
- class Endpoint
3
- class ResponseCodes
4
- RESPONSE_CODES = 'responseCodes'.freeze
5
- DESCRIPTION = 'description'.freeze
6
- SUCCESSFUL = 'successful'.freeze
2
+ module Json
3
+ class ResponseCodes < Schema
7
4
  STATUS = 'status'.freeze
5
+ SUCCESSFUL = 'successful'.freeze
6
+ DESCRIPTION = 'description'.freeze
7
+
8
+ def initialize(schema, options = {})
9
+ @parent_property = 'responseCodes'
8
10
 
9
- def initialize(schema)
10
- @schema = schema
11
- @schema[RESPONSE_CODES] ||= []
11
+ super
12
12
  end
13
13
 
14
- def add(status_code, successful, options = {})
15
- response_code = {
16
- STATUS => status_code,
17
- SUCCESSFUL => successful,
18
- DESCRIPTION => options.fetch(:description, '')
19
- }
14
+ def merge!(status_code, successful)
15
+ return if exists?(status_code, successful)
20
16
 
21
- Lurker::SchemaModifier.append!(@schema[RESPONSE_CODES], response_code)
17
+ payload = {STATUS => status_code, SUCCESSFUL => successful, DESCRIPTION => ''}
18
+ @schema << Lurker::Json::Parser.plain(root_schema: root_schema).parse(payload)
22
19
  end
23
20
 
24
21
  def validate!(status_code, successful)
@@ -31,7 +28,7 @@ module Lurker
31
28
  end
32
29
 
33
30
  def exists?(status_code, successful)
34
- !!@schema[RESPONSE_CODES].detect do |response_code|
31
+ !!@schema.detect do |response_code|
35
32
  response_code[SUCCESSFUL] == successful &&
36
33
  (response_code[STATUS] == status_code || # 200
37
34
  response_code[STATUS].to_i == status_code) # "200 OK"
@@ -0,0 +1,17 @@
1
+ module Lurker
2
+ module Json
3
+ module Tuple
4
+ class AllOf < Json::Schema
5
+ include Tuple::InstanceMethods
6
+
7
+ ALLOF = 'allOf'.freeze
8
+
9
+ private
10
+
11
+ def tuple_key
12
+ ALLOF
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Lurker
2
+ module Json
3
+ module Tuple
4
+ class AnyOf < Json::Schema
5
+ include Tuple::InstanceMethods
6
+
7
+ ANYOF = 'anyOf'.freeze
8
+
9
+ private
10
+
11
+ def tuple_key
12
+ ANYOF
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Lurker
2
+ module Json
3
+ module Tuple
4
+ class OneOf < Json::Schema
5
+ include Tuple::InstanceMethods
6
+
7
+ ONEOF = 'oneOf'.freeze
8
+
9
+ private
10
+
11
+ def tuple_key
12
+ ONEOF
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ module Lurker
2
+ module Json
3
+ module Tuple
4
+ module InstanceMethods
5
+ def merge!(schema)
6
+ return if exists?(schema)
7
+
8
+ @schema[tuple_key] << @parser.typed.parse_property(
9
+ parent_property, schema)
10
+ end
11
+
12
+ def replace!(schema)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def exists?(schema)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ private
21
+
22
+ def parse_schema(schema)
23
+ @schema = {}
24
+ initialize_properties
25
+
26
+ schema = schema.dup
27
+ @schema[tuple_key] = (schema.delete(tuple_key) || schema).map do |payload|
28
+ @parser.typed.parse_property(parent_property, payload)
29
+ end
30
+ end
31
+
32
+ def initialize_properties
33
+ @schema[tuple_key] ||= []
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,122 @@
1
+ module Lurker
2
+ module Json
3
+ class Schema
4
+ include Lurker::Json::Concerns::Validatable
5
+
6
+ EXTENSIONS = 'extensions'.freeze
7
+ RESPONSE_CODES = 'responseCodes'.freeze
8
+ REQUEST_PARAMETERS = 'requestParameters'.freeze
9
+ RESPONSE_PARAMETERS = 'responseParameters'.freeze
10
+
11
+ attr_reader :uri, :root_schema, :parent_schema, :parent_property
12
+
13
+ def initialize(schema, options = {})
14
+ @root_schema = options[:root_schema]
15
+ @parent_schema = options[:parent_schema]
16
+ @parent_property = options[:parent_property]
17
+ @uri = parse_uri(options[:uri])
18
+
19
+ @parser = Lurker::Json::Parser.new(subschema_options)
20
+
21
+ parse_schema(schema)
22
+ end
23
+
24
+ def root?
25
+ root_schema.blank?
26
+ end
27
+
28
+ def merge!(schema)
29
+ return if schema.blank?
30
+
31
+ schema.each do |property, property_schema|
32
+ if @schema[property].is_a?(Lurker::Json::Schema)
33
+ @schema[property].merge!(property_schema)
34
+
35
+ next
36
+ end
37
+
38
+ replace!(property, property_schema)
39
+ end
40
+ end
41
+
42
+ def replace!(property, property_schema)
43
+ @schema[property] = Lurker::Json::Parser.plain(subschema_options)
44
+ .parse_property(property, property_schema)
45
+ end
46
+
47
+ def reorder!
48
+ @schema = Hash[@schema.sort]
49
+ self
50
+ end
51
+
52
+ def to_hash(options = {})
53
+ hashify(@schema, options)
54
+ end
55
+
56
+ def to_json(options = {})
57
+ hashify(@schema, options).to_json
58
+ end
59
+
60
+ def to_yaml(options = {})
61
+ YAML.dump(to_hash(options))
62
+ end
63
+
64
+ def method_missing(method, *args, &block)
65
+ if @schema.is_a?(Lurker::Json::Schema) || @schema.respond_to?(method)
66
+ return @schema.send(method, *args, &block)
67
+ end
68
+
69
+ super
70
+ end
71
+
72
+ private
73
+
74
+ def hashify(object, options = {})
75
+ case object
76
+ when Lurker::Json::Reference
77
+ options[:reference] == :original ? object.to_original_hash(options)
78
+ : object.to_hash(options)
79
+ when Lurker::Json::Schema then object.to_hash(options)
80
+ when Array then object.map { |x| hashify(x, options) }
81
+ when Hash
82
+ object.each_with_object({}) do |(property, property_schema), memo|
83
+ memo[property] = hashify(property_schema, options)
84
+ end
85
+ else object
86
+ end
87
+ end
88
+
89
+ def parse_uri(uri)
90
+ return if uri.blank?
91
+
92
+ uri = uri.respond_to?(:scheme) ? uri : URI.parse(uri)
93
+ uri.relative? ? URI.parse("file://#{uri}") : uri
94
+ end
95
+
96
+ def parse_schema(schema)
97
+ @schema = {}
98
+
99
+ unless schema.is_a?(Hash)
100
+ return @schema = @parser.plain.parse(schema)
101
+ end
102
+
103
+ schema.each do |property, property_schema|
104
+ @schema[property] = case property
105
+ when EXTENSIONS
106
+ Lurker::Json::Extensions.new(property_schema, subschema_options)
107
+ when RESPONSE_CODES
108
+ Lurker::Json::ResponseCodes.new(property_schema, subschema_options)
109
+ when REQUEST_PARAMETERS, RESPONSE_PARAMETERS
110
+ @parser.typed.parse_property(property, property_schema)
111
+ else
112
+ @parser.plain.parse_property(property, property_schema)
113
+ end
114
+ end
115
+ end
116
+
117
+ def subschema_options
118
+ {uri: uri, root_schema: (root? ? self : root_schema), parent_schema: self}
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,58 @@
1
+ module Lurker
2
+ module Json
3
+ class Writter
4
+ class << self
5
+ def write(schema, path)
6
+ new(path).write(schema)
7
+ end
8
+ end
9
+
10
+ def initialize(path)
11
+ @path = path
12
+ @dirname = File.dirname(path)
13
+ end
14
+
15
+ def write(schema)
16
+ write_to_file(schema)
17
+
18
+ extract_references(schema).each do |reference|
19
+ Lurker::Json::Writter.write(reference, reference.original_uri.path)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # TODO : Separate schema dumping for JSON & YAML files
26
+ def write_to_file(schema)
27
+ FileUtils.mkdir_p(@dirname) unless File.directory?(@dirname)
28
+ File.open(@path, File::WRONLY | File::TRUNC | File::CREAT) do |file|
29
+ file.write(present_by_extension schema)
30
+ end
31
+ end
32
+
33
+ def extract_references(schema, memo = [])
34
+ case schema
35
+ when Array
36
+ schema.each { |payload| extract_references(payload, memo) }
37
+ when Hash, Lurker::Json::Schema
38
+ schema.each do |_, payload|
39
+ memo << payload if payload.is_a?(Lurker::Json::Reference)
40
+ extract_references(payload, memo)
41
+ end
42
+ else
43
+ # no-op
44
+ end
45
+
46
+ memo
47
+ end
48
+
49
+ def present_by_extension(schema)
50
+ case File.extname(@path)
51
+ when '.yml' then schema.to_yaml(reference: :original)
52
+ when '.json' then JSON.pretty_generate(schema.to_hash reference: :original)
53
+ else raise TypeError, "Unknown schema file extension '#{File.extname(@path)}'"
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -115,7 +115,7 @@ class Lurker::EndpointPresenter < Lurker::BasePresenter
115
115
  # TODO: remove in favor of named_path
116
116
  def path
117
117
  return @path if @path
118
- unless (@path = @endpoint.schema.extensions.try(:[], 'path_info')).present?
118
+ unless (@path = @endpoint.schema['extensions'].try(:[], 'path_info')).present?
119
119
  @path = @endpoint.path.gsub(/__/, ':')
120
120
  @path = @path.gsub(/-#{@end}/) if @endpoint.schema.extensions.try(:[], 'suffix').present?
121
121
  end
@@ -127,7 +127,7 @@ class Lurker::EndpointPresenter < Lurker::BasePresenter
127
127
  def named_path
128
128
  return @named_path if @named_path
129
129
  @named_path = base_path.sub(/\/?$/, '/') + endpoint.path.gsub(/__/, ':')
130
- if (suffix = endpoint.schema.extensions.try(:[], 'suffix')).present?
130
+ if (suffix = endpoint.schema['extensions'].try(:[], 'suffix')).present?
131
131
  @named_path = @named_path.gsub(/-#{suffix}/, '')
132
132
  end
133
133
  @named_path
@@ -48,7 +48,10 @@ class Lurker::SchemaPresenter < Lurker::BasePresenter
48
48
  html << enum_html
49
49
 
50
50
  (@schema.keys - FORMATTED_KEYS).each do |key|
51
- html << '<li>%s: %s</li>' % [key, @schema[key]]
51
+ value = @schema[key]
52
+ value = value.to_hash if value.is_a?(Lurker::Json::Schema)
53
+
54
+ html << '<li>%s: %s</li>' % [key, value]
52
55
  end
53
56
 
54
57
  html << items_html
@@ -22,12 +22,12 @@ class Lurker::ServicePresenter < Lurker::BasePresenter
22
22
  end
23
23
 
24
24
  def domains
25
- return service.domains if service.domains.present?
25
+ return service_domains if service_domains.present?
26
26
  { '/' => 'Local' }
27
27
  end
28
28
 
29
29
  def default_domain
30
- return service.domains.to_a[0][1] if service.domains.present?
30
+ return service_domains.to_a[0][1] if service_domains.present?
31
31
  '/'
32
32
  end
33
33
 
@@ -87,4 +87,10 @@ class Lurker::ServicePresenter < Lurker::BasePresenter
87
87
  hash
88
88
  end
89
89
  end
90
+
91
+ private
92
+
93
+ def service_domains
94
+ service.domains.to_hash
95
+ end
90
96
  end