Class: Metaschema::RubySourceEmitter
- Inherits:
-
Object
- Object
- Metaschema::RubySourceEmitter
- Defined in:
- lib/metaschema/ruby_source_emitter.rb
Overview
Emits Ruby source code from generated metaschema classes.
After ModelGenerator#generate creates in-memory classes, this class introspects them and emits equivalent Ruby source code that can be saved to .rb files and loaded with ‘require`.
Handles three kinds of type references:
-
Builtin types (:string, :integer, etc.) — emitted as symbol literals
-
Generated types (in @classes) — emitted as fully-qualified string refs
-
Framework types (named, from other gems) — emitted as bare class refs
-
Anonymous inline types — collected and emitted as separate named classes
Usage:
files = Metaschema::ModelGenerator.to_ruby_source(
"oscal_complete_metaschema.xml",
module_name: "Oscal::V1_2_1"
)
files.each { |name, source| File.write(name, source) }
Constant Summary collapse
- BUILTIN_TYPES =
%i[string integer boolean float date time datetime symbol].freeze
- RESERVED_CLASS_NAMES =
%w[Base Hash Method Object Class Module].freeze
Instance Method Summary collapse
- #emit ⇒ Object
-
#emit_split ⇒ Object
Emit as separate files per root model type.
-
#initialize(classes, module_name, generator) ⇒ RubySourceEmitter
constructor
A new instance of RubySourceEmitter.
Constructor Details
#initialize(classes, module_name, generator) ⇒ RubySourceEmitter
Returns a new instance of RubySourceEmitter.
28 29 30 31 32 33 34 |
# File 'lib/metaschema/ruby_source_emitter.rb', line 28 def initialize(classes, module_name, generator) @classes = classes @module_name = module_name @generator = generator @class_name_cache = {} @anon_name_map = {} # anonymous class → assigned name end |
Instance Method Details
#emit ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/metaschema/ruby_source_emitter.rb', line 36 def emit sorted = sort_classes collect_anonymous_types(sorted) files = {} source = emit_module_header # Emit anonymous types first (they're dependencies of named classes) @anon_name_map.each_value do |anon_name| anon_class = @anon_name_map.key(anon_name) source += "\n#{emit_anonymous_class(anon_name, anon_class)}" end sorted.each do |key, klass| next unless klass.is_a?(Class) && klass < Lutaml::Model::Serializable source += "\n#{emit_class(key, klass)}" end source += files["all_models.rb"] = source files end |
#emit_split ⇒ Object
Emit as separate files per root model type.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/metaschema/ruby_source_emitter.rb', line 61 def emit_split sorted = sort_classes collect_anonymous_types(sorted) root_classes = find_root_classes emitted = Set.new files = {} root_classes.each do |root_key, root_klass| deps = find_dependencies(root_key, root_klass) all_keys = ([root_key] + deps).uniq source = emit_module_header # Emit anonymous types needed by this root's dependency tree emit_anon_deps_for(all_keys, source) all_keys.each do |key| klass = @classes[key] next unless klass.is_a?(Class) && klass < Lutaml::Model::Serializable next if emitted.include?(key) source += "\n#{emit_class(key, klass)}" emitted.add(key) end source += filename = clean_class_name(root_key).gsub(/([a-z])([A-Z])/, '\1_\2').downcase + ".rb" files[filename] = source end # Emit any remaining classes not covered by roots remaining = sorted.except(*emitted) unless remaining.empty? source = emit_module_header remaining.each do |key, klass| next unless klass.is_a?(Class) && klass < Lutaml::Model::Serializable source += "\n#{emit_class(key, klass)}" end source += files["common.rb"] = source end files end |