Module: Scjson
- Defined in:
- lib/scjson.rb,
lib/scjson/cli.rb,
lib/scjson/version.rb
Overview
Agent Name: ruby-scjson-version
Part of the scjson project. Developed by Softoboros Technology Inc. Licensed under the BSD 1-Clause License.
Constant Summary collapse
- XMLNS =
'http://www.w3.org/2005/07/scxml'.freeze
- ATTRIBUTE_MAP =
{ 'datamodel' => 'datamodel_attribute', 'initial' => 'initial_attribute', 'type' => 'type_value', 'raise' => 'raise_value' }.freeze
- COLLAPSE_ATTRS =
%w[expr cond event target delay location name src id].freeze
- SCXML_ELEMENTS =
%w[ scxml state parallel final history transition invoke finalize datamodel data onentry onexit log send cancel raise assign script foreach param if elseif else content donedata initial ].freeze
- STRUCTURAL_FIELDS =
%w[ state parallel final history transition invoke finalize datamodel data onentry onexit log send cancel raise assign script foreach param if_value elseif else_value raise_value content donedata initial ].freeze
- PRESERVE_EMPTY_KEYS =
%w[expr cond event target id name label text].freeze
- ALWAYS_KEEP_KEYS =
%w[else_value else final onentry].freeze
- VERSION =
'0.1.4'
Class Method Summary collapse
-
.convert_scjson_file(src, dest, verify) ⇒ void
Convert a single scjson document to SCXML.
-
.convert_scxml_file(src, dest, verify, keep_empty) ⇒ void
Convert a single SCXML document to scjson.
-
.handle_json(path, opt) ⇒ void
Convert SCXML inputs to scjson outputs.
-
.handle_xml(path, opt) ⇒ void
Convert scjson inputs to SCXML outputs.
-
.help_text ⇒ String
Render the help text describing CLI usage.
-
.json_to_xml(json_str) ⇒ String
Convert a canonical scjson document back to SCXML.
-
.main(argv = ARGV) ⇒ void
Command line interface for scjson conversions.
-
.splash ⇒ void
Display the CLI program header.
-
.validate(path, recursive) ⇒ void
Validate a file or directory tree of SCXML and scjson documents.
-
.validate_file(src) ⇒ Boolean
Validate a single SCXML or scjson document by round-tripping.
-
.xml_to_json(xml_str, omit_empty = true) ⇒ String
Convert an SCXML document to its canonical scjson form.
Class Method Details
.convert_scjson_file(src, dest, verify) ⇒ void
This method returns an undefined value.
Convert a single scjson document to SCXML.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/scjson/cli.rb', line 158 def self.convert_scjson_file(src, dest, verify) json_str = File.read(src) begin xml_str = Scjson.json_to_xml(json_str) if verify Scjson.xml_to_json(xml_str) puts "Verified #{src}" else FileUtils.mkdir_p(dest.dirname) File.write(dest, xml_str) puts "Wrote #{dest}" end rescue StandardError => e warn "Failed to convert #{src}: #{e}" end end |
.convert_scxml_file(src, dest, verify, keep_empty) ⇒ void
This method returns an undefined value.
Convert a single SCXML document to scjson.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/scjson/cli.rb', line 134 def self.convert_scxml_file(src, dest, verify, keep_empty) xml_str = File.read(src) begin json_str = Scjson.xml_to_json(xml_str, !keep_empty) if verify Scjson.json_to_xml(json_str) puts "Verified #{src}" else FileUtils.mkdir_p(dest.dirname) File.write(dest, json_str) puts "Wrote #{dest}" end rescue StandardError => e warn "Failed to convert #{src}: #{e}" end end |
.handle_json(path, opt) ⇒ void
This method returns an undefined value.
Convert SCXML inputs to scjson outputs.
Handles both file and directory inputs, preserving relative paths when writing to directories.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/scjson/cli.rb', line 78 def self.handle_json(path, opt) if path.directory? out_dir = opt[:output] ? Pathname.new(opt[:output]) : path pattern = opt[:recursive] ? '**/*.scxml' : '*.scxml' Dir.glob(path.join(pattern).to_s).each do |src| rel = Pathname.new(src).relative_path_from(path) dest = out_dir.join(rel).sub_ext('.scjson') convert_scxml_file(src, dest, opt[:verify], opt[:keep_empty]) end else dest = if opt[:output] p = Pathname.new(opt[:output]) p.directory? ? p.join(path.basename.sub_ext('.scjson')) : p else path.sub_ext('.scjson') end convert_scxml_file(path, dest, opt[:verify], opt[:keep_empty]) end end |
.handle_xml(path, opt) ⇒ void
This method returns an undefined value.
Convert scjson inputs to SCXML outputs.
Handles both file and directory inputs.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/scjson/cli.rb', line 106 def self.handle_xml(path, opt) if path.directory? out_dir = opt[:output] ? Pathname.new(opt[:output]) : path pattern = opt[:recursive] ? '**/*.scjson' : '*.scjson' Dir.glob(path.join(pattern).to_s).each do |src| rel = Pathname.new(src).relative_path_from(path) dest = out_dir.join(rel).sub_ext('.scxml') convert_scjson_file(src, dest, opt[:verify]) end else dest = if opt[:output] p = Pathname.new(opt[:output]) p.directory? ? p.join(path.basename.sub_ext('.scxml')) : p else path.sub_ext('.scxml') end convert_scjson_file(path, dest, opt[:verify]) end end |
.help_text ⇒ String
Render the help text describing CLI usage.
65 66 67 |
# File 'lib/scjson/cli.rb', line 65 def self.help_text 'scjson - SCXML <-> scjson converter and validator' end |
.json_to_xml(json_str) ⇒ String
Convert a canonical scjson document back to SCXML.
63 64 65 66 67 68 69 70 71 |
# File 'lib/scjson.rb', line 63 def json_to_xml(json_str) data = JSON.parse(json_str) remove_empty(data) doc = Nokogiri::XML::Document.new doc.encoding = 'utf-8' root = build_element(doc, 'scxml', data) doc.root = root doc.to_xml end |
.main(argv = ARGV) ⇒ void
This method returns an undefined value.
Command line interface for scjson conversions.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/scjson/cli.rb', line 28 def self.main(argv = ARGV) = { recursive: false, verify: false, keep_empty: false } cmd = argv.shift if cmd.nil? || %w[-h --help].include?(cmd) puts(help_text) return end parser = OptionParser.new do |opts| opts. = '' opts.on('-o', '--output PATH', 'output file or directory') { |v| [:output] = v } opts.on('-r', '--recursive', 'recurse into directories') { [:recursive] = true } opts.on('-v', '--verify', 'verify conversion without writing output') { [:verify] = true } opts.on('--keep-empty', 'keep null or empty items when producing JSON') { [:keep_empty] = true } end path = argv.shift parser.parse!(argv) unless path puts(help_text) return end splash case cmd when 'json' handle_json(Pathname.new(path), ) when 'xml' handle_xml(Pathname.new(path), ) when 'validate' validate(Pathname.new(path), [:recursive]) else puts(help_text) end end |
.splash ⇒ void
This method returns an undefined value.
Display the CLI program header.
19 20 21 |
# File 'lib/scjson/cli.rb', line 19 def self.splash puts "scjson #{VERSION} - SCXML <-> scjson converter" end |
.validate(path, recursive) ⇒ void
This method returns an undefined value.
Validate a file or directory tree of SCXML and scjson documents.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/scjson/cli.rb', line 181 def self.validate(path, recursive) success = true if path.directory? pattern = recursive ? '**/*' : '*' Dir.glob(path.join(pattern).to_s).each do |f| next unless File.file?(f) next unless f.end_with?('.scxml', '.scjson') success &= validate_file(f) end else success &= validate_file(path.to_s) end exit(1) unless success end |
.validate_file(src) ⇒ Boolean
Validate a single SCXML or scjson document by round-tripping.
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/scjson/cli.rb', line 201 def self.validate_file(src) begin data = File.read(src) if src.end_with?('.scxml') json = Scjson.xml_to_json(data) Scjson.json_to_xml(json) elsif src.end_with?('.scjson') xml = Scjson.json_to_xml(data) Scjson.xml_to_json(xml) else return true end true rescue StandardError => e warn "Validation failed for #{src}: #{e}" false end end |
.xml_to_json(xml_str, omit_empty = true) ⇒ String
Convert an SCXML document to its canonical scjson form.
47 48 49 50 51 52 53 54 55 56 |
# File 'lib/scjson.rb', line 47 def xml_to_json(xml_str, omit_empty = true) doc = Nokogiri::XML(xml_str) { |cfg| cfg.strict.nonet } root = locate_root(doc) raise ArgumentError, 'Document missing <scxml> root element' unless root map = element_to_hash(root) collapse_whitespace(map) remove_empty(map) if omit_empty JSON.pretty_generate(map) end |