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