lib/prmd/commands/combine.rb in prmd-0.6.2 vs lib/prmd/commands/combine.rb in prmd-0.7.0
- old
+ new
@@ -1,73 +1,100 @@
+require 'prmd/load_schema_file'
+require 'prmd/core/schema_hash'
+require 'prmd/core/combiner'
+
+# :nodoc:
module Prmd
- def self.combine(path, options={})
- files = if File.directory?(path)
- Dir.glob(File.join(path, '**', '*.json')) +
- Dir.glob(File.join(path, '**', '*.yaml')) -
- [options[:meta]]
- else
- [path]
+ # Schema combine
+ module Combine
+ # @api private
+ # @param [#size] given
+ # @param [#size] expected
+ # @return [void]
+ def self.handle_faulty_load(given, expected)
+ unless given.size == expected.size
+ abort 'Somes files have failed to parse. ' \
+ 'If you wish to continue without them,' \
+ 'please enable faulty_load using --faulty-load'
+ end
end
- # sort for stable loading on any platform
- schemata = []
- files.sort.each do |file|
- begin
- schemata << [file, YAML.load(File.read(file))]
- rescue
- $stderr.puts "unable to parse #{file}"
+
+ # @api private
+ # @param [Array<String>] paths
+ # @param [Hash<Symbol, Object>] options
+ # @return [Array<String>] list of filenames from paths
+ def self.crawl_map(paths, options = {})
+ files = [*paths].map do |path|
+ if File.directory?(path)
+ Dir.glob(File.join(path, '**', '*.{json,yml,yaml}'))
+ else
+ path
+ end
end
+ files.flatten!
+ files.delete(options[:meta])
+ files
end
- unless schemata.length == files.length
- exit(1) # one or more files failed to parse
- end
- data = {
- '$schema' => 'http://json-schema.org/draft-04/hyper-schema',
- 'definitions' => {},
- 'properties' => {},
- 'type' => ['object']
- }
-
- # tracks which entities where defined in which file
- schemata_map = {}
-
- if options[:meta] && File.exists?(options[:meta])
- data.merge!(YAML.load(File.read(options[:meta])))
+ # @api private
+ # @param [String] filename
+ # @return [SchemaHash]
+ def self.load_schema_hash(filename)
+ data = Prmd.load_schema_file(filename)
+ SchemaHash.new(data, filename: filename)
end
- schemata.each do |schema_file, schema_data|
- id = schema_data['id'].split('/').last
-
- if file = schemata_map[schema_data['id']]
- $stderr.puts "`#{schema_data['id']}` (from #{schema_file}) was already defined in `#{file}` and will overwrite the first definition"
+ # @api private
+ # @param [Array<String>] files
+ # @param [Hash<Symbol, Object>] options
+ # @return [Array<SchemaHash>] schema hashes
+ def self.load_files(files, options = {})
+ files.each_with_object([]) do |filename, result|
+ begin
+ result << load_schema_hash(filename)
+ rescue JSON::ParserError, Psych::SyntaxError => ex
+ $stderr.puts "unable to parse #{filename} (#{ex.inspect})"
+ end
end
- schemata_map[schema_data['id']] = schema_file
+ end
- # schemas are now in a single scope by combine
- schema_data.delete('id')
+ # @api private
+ # @param [Array<String>] paths
+ # @param [Hash<Symbol, Object>] options
+ # @return (see .load_files)
+ def self.load_schemas(paths, options = {})
+ files = crawl_map(paths, options)
+ # sort for stable loading on any platform
+ schemata = load_files(files.sort, options)
+ handle_faulty_load(schemata, files) unless options[:faulty_load]
+ schemata
+ end
- data['definitions']
- data['definitions'][id] = schema_data
- reference_localizer = lambda do |datum|
- case datum
- when Array
- datum.map {|element| reference_localizer.call(element)}
- when Hash
- if datum.has_key?('$ref')
- datum['$ref'] = '#/definitions' + datum['$ref'].gsub('#', '').gsub('/schemata', '')
- end
- if datum.has_key?('href') && datum['href'].is_a?(String)
- datum['href'] = datum['href'].gsub('%23', '').gsub(%r{%2Fschemata(%2F[^%]*%2F)}, '%23%2Fdefinitions\1')
- end
- datum.each { |k,v| datum[k] = reference_localizer.call(v) }
- else
- datum
- end
- end
- reference_localizer.call(data['definitions'][id])
+ # Merges all found schema files in the given paths into a single Schema
+ #
+ # @param [Array<String>] paths
+ # @param [Hash<Symbol, Object>] options
+ # @return (see Prmd::Combiner#combine)
+ def self.combine(paths, options = {})
+ schemata = load_schemas(paths)
+ base = Prmd::Template.load_json('combine_head.json')
+ schema = base['$schema']
+ meta = {}
+ meta = Prmd.load_schema_file(options[:meta]) if options[:meta]
+ combiner = Prmd::Combiner.new(meta: meta, base: base, schema: schema)
+ combiner.combine(*schemata)
+ end
- data['properties'][id] = { '$ref' => "#/definitions/#{id}" }
+ class << self
+ private :handle_faulty_load
+ private :crawl_map
+ private :load_schema_hash
+ private :load_files
+ private :load_schemas
end
+ end
- Prmd::Schema.new(data)
+ # (see Prmd::Combine.combine)
+ def self.combine(paths, options = {})
+ Combine.combine(paths, { faulty_load: false }.merge(options))
end
end