lib/scaffold_parser/scaffolders/xsd.rb in scaffold_parser-0.5.0 vs lib/scaffold_parser/scaffolders/xsd.rb in scaffold_parser-0.6.0

- old
+ new

@@ -1,59 +1,61 @@ require 'scaffold_parser/scaffolders/xsd/parser' -require 'scaffold_parser/scaffolders/xsd/builder' +require 'scaffold_parser/scaffolders/xsd/parser/handlers/utils' module ScaffoldParser module Scaffolders class XSD - def self.call(doc, options) - self.new(doc, options).call + include Parser::Handlers::Utils + + def self.call(doc, options, parse_options = {}) + self.new(doc, options, parse_options).call end - def initialize(doc, options) + def initialize(doc, options, parse_options = {}) @doc = doc @options = options + @parse_options = parse_options end def call - puts "Starting collectiong elements to scaffold" if @options[:verbose] + all = [@doc.schema] + @doc.schema.collect_included_schemas(@parse_options) + @doc.schema.collect_imported_schemas(@parse_options) - unscaffolded_elements = collect_unscaffolded_subelements(@doc) + @doc.submodel_nodes + classes = Parser.call(all, @options) - puts "Collected #{unscaffolded_elements.size} elements to scaffold" if @options[:verbose] + classes.each do |klass| + klass.methods = klass.methods.map do |meth| + if meth.is_a?(Parser::Handlers::SubmodelMethod) && !classes.map(&:name).include?(meth.submodel_class) + meth.to_at_method + else + meth + end + end + end - code = unscaffolded_elements.flat_map do |element| - [Parser.call(element.definition, @options), Builder.call(element.definition, @options)] + classes.each do |klass| + klass.namespace = @options[:namespace] end - code.push ['parsers/base_parser.rb', base_parser_template] - code.push ['builders/base_builder.rb', base_builder_template] + classes.flat_map do |class_template| + [["parsers/#{class_template.name.underscore}.rb", class_template.to_s], + ["builders/#{class_template.name.underscore}.rb", class_template.to_builder_s], + ["parsers/base_parser.rb", wrap_in_namespace(base_parser_template, @options[:namespace])], + ["builders/base_builder.rb", wrap_in_namespace(base_builder_template, @options[:namespace])], + ["requires.rb", create_requires_template(classes)], + ["hash_with_attrs.rb", wrap_in_namespace(hash_with_attrs_template, @options[:namespace])], + ["mega.rb", wrap_in_namespace(mega_template, @options[:namespace])] + ] + end end private - def collect_unscaffolded_subelements(node, collected = []) - subelements = node.definition.submodel_nodes.to_a + node.definition.array_nodes.map(&:list_element) - .reject(&:xs_type?) - .reject { |node| collected.include?(node.to_class_name) } - - subelements.each do |element| - if collected.none? { |c| c.to_class_name == element.to_class_name } - collected << element - - puts "Collected #{element.to_name} element" if @options[:verbose] - - collect_unscaffolded_subelements(element, collected) - end - end - - collected - end - def base_parser_template <<~TEMPLATE module Parsers module BaseParser + include Mega EMPTY_ARRAY = [] attr_accessor :raw def initialize(raw) @@ -93,31 +95,44 @@ elements.map do |element| klass.new(element) end end + + def to_h_with_attrs + hash = HashWithAttributes.new({}, attributes) + + hash + end end end TEMPLATE end def base_builder_template <<~TEMPLATE module Builders module BaseBuilder - attr_accessor :name, :data + attr_accessor :name, :data, :options - def initialize(name, data = {}) + def initialize(name, data = {}, options = {}) @name = name @data = data || {} + @options = options || {} end def to_xml - doc = Ox::Document.new(version: '1.0') + encoding = options[:encoding] + + doc_options = { version: '1.0' } + doc_options[:encoding] = encoding if encoding + doc = Ox::Document.new(doc_options) doc << builder - Ox.dump(doc, with_xml: true) + dump_options = { with_xml: true } + dump_options[:encoding] = encoding if encoding + Ox.dump(doc, dump_options) end def build_element(name, content) element = Ox::Element.new(name) if content.respond_to? :attributes @@ -132,9 +147,101 @@ element end end end TEMPLATE + end + + def hash_with_attrs_template + <<~TEMPLATE + class HashWithAttributes + def initialize(hash, attributes = nil) + @hash = hash + @attributes = attributes if attributes + end + + def value + @hash + end + + def attributes + @attributes ||= {} + end + + def attributes=(attributes) + @attributes = attributes + end + + def ==(other) + if other.respond_to?(:value) && other.respond_to?(:attributes) + value == other.value && other.attributes == attributes + else + value == other + end + end + + def merge(other) + merged_hash = value.merge other.value + merged_attrs = attributes.merge other.attributes + + self.class.new(merged_hash, merged_attrs) + end + + def key?(key) + value.key? key + end + + def [](key) + value[key] + end + + def []=(key, key_value) + value[key] = key_value + end + + def dig(*attrs) + value.dig(*attrs) + end + end + TEMPLATE + end + + def mega_template + <<~TEMPLATE + module Mega + def mega + called_from = caller_locations[0].label + included_modules = (self.class.included_modules - Class.included_modules - [Mega]) + included_modules.map { |m| m.instance_method(called_from).bind(self).call } + end + end + TEMPLATE + end + + def create_requires_template(classes) + modules = classes.select { |cl| cl.is_a? Parser::Handlers::Module } + classes = classes.select { |cl| cl.is_a? Parser::Handlers::Klass } + with_inheritance, others = classes.partition { |klass| klass.inherit_from } + + requires = ['parsers/base_parser', 'builders/base_builder'] + modules.each do |klass| + requires << "parsers/#{klass.name.underscore}" + requires << "builders/#{klass.name.underscore}" + end + others.each do |klass| + requires << "parsers/#{klass.name.underscore}" + requires << "builders/#{klass.name.underscore}" + end + with_inheritance.each do |klass| + requires << "parsers/#{klass.name.underscore}" + requires << "builders/#{klass.name.underscore}" + end + + if @options[:namespace] + requires = requires.map { |r| r.prepend("#{@options[:namespace].underscore}/") } + end + + requires.map { |r| "require '#{r}'" }.join("\n") end end end end