Skip to content

Instantly share code, notes, and snippets.

@nanki
Created February 12, 2012 18:06
Show Gist options
  • Save nanki/025918d5007284ce4fe9 to your computer and use it in GitHub Desktop.
Save nanki/025918d5007284ce4fe9 to your computer and use it in GitHub Desktop.
sugary mappingml.
#!/usr/bin/env ruby
require 'nokogiri'
SEPARATOR = '->'
class ClassInfo
attr_reader :packageName, :name
def initialize(qualified_name)
names = qualified_name.split '.'
@name = names.pop
@packageName = names.join '.'
end
end
class ClassTranslation
attr_reader :from, :to
attr_reader :members
def initialize(from, to)
@from = ClassInfo.new from
@to = ClassInfo.new to
@members = []
end
def append(member)
@members << member
end
def build(doc)
doc.class_ :name => @from.name do
doc.target :packageName => @to.packageName, :name => @to.name
@members.each do |mt|
mt.build doc
end
end
end
end
class MemberTranslation
IDENTIFIER = /[$_A-Za-z][$_A-Za-z0-9]*/
class Name < Struct.new(:name);end
class Constructor < Struct.new(:signature)
def build(doc, &block)
doc.constructor :signature => signature, &block
end
end
class Method < Struct.new(:name, :signature)
def build(doc, &block)
doc.method_ :name => name, :signature => signature, &block
end
def to_target
if signature == "(...)"
Simple.new name
else
FullString.new "@0.#{name}#{signature}"
end
end
end
class Field < Name
def build(doc, &block)
doc.field :name => name, &block
end
def to_target
Simple.new name
end
end
# for target
module Target
def to_target
self
end
end
class Simple < Name
include Target
def build(doc)
doc.target :name => name
end
end
class PropertySet < Simple
def build(doc)
doc.target :propertySet => name
end
end
class PropertyGet < Simple
def build(doc)
doc.target :propertyGet => name
end
end
class FullString < Struct.new(:string)
include Target
def build(doc)
doc.target do
doc.format do
doc.cdata string
end
end
end
end
def initialize(from, to)
@from = build_from(from)
@to = build_target(to)
if [@from, @to].map(&:class) == [Field, PropertyGet]
@to = Field.new @to.name
end
@to = @to.to_target
end
def build(doc)
@from.build doc do
@to.build doc
end
end
private
def build_from(str)
case str
when /^@constructor(\(.*\))$/
Constructor.new $1
when /^\.(#{IDENTIFIER})$/
Field.new $1
when /^\.(#{IDENTIFIER})(\(.*\))$/
Method.new $1, $2
else
raise "error with - #{str}"
end
end
def build_target(str)
case str
when /^\.(#{IDENTIFIER})\s*=\s*(\.\.\.)?$/
PropertySet.new $1
when /^\.(#{IDENTIFIER})$/
PropertyGet.new $1
when /^\.(#{IDENTIFIER})(\(.*\))$/
Method.new $1, $2
else
FullString.new str
end
end
end
packages = Hash.new{[]}
last = nil
top_indent = 0
ARGF.each_with_index do |line, lineno|
lineno += 1
md = /^ */.match line
indent = md ? md[0].length : 0
line.sub!(%r|//.*$|, '')
line.strip!
next if line.empty?
trans_args = line.split(SEPARATOR).map! &:strip!
raise "Syntax error at line #{lineno+1}" if trans_args.size != 2
if packages.empty? || indent == top_indent
last = ct = ClassTranslation.new(*trans_args)
packages[ct.from.packageName] <<= ct
top_indent = indent
elsif indent > top_indent
last.append MemberTranslation.new(*trans_args)
end
end
builder = Nokogiri::XML::Builder.new do |doc|
doc.mapping do
doc.packages do
packages.each do |packageName, cts|
doc.package :name => packageName do
cts.each do |ct|
ct.build doc
end
end
end
end
end
end
puts builder.to_xml.to_s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment