Class: DslRuntime

Inherits:
Object
  • Object
show all
Includes:
Utils
Defined in:
lib/roundtrip_xml/dsl_runtime.rb

Overview

Class which evaluates DSL and read XML files to populate the namespace with classes

Constant Summary

Constants included from Utils

Utils::VAR_SUFIX

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utils

included, #name_to_sym, #new_roxml_class

Constructor Details

#initializeDslRuntime

Returns a new instance of DslRuntime.



14
15
16
17
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 14

def initialize()
  @classes = {}
  @root_classes = Set.new
end

Class Method Details

.load(path) ⇒ Object



175
176
177
178
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 175

def self.load(path)
  file = File.open path, 'r'
  Marshal.load file
end

Instance Method Details

#add_class(name, clazz) ⇒ Object



52
53
54
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 52

def add_class(name, clazz)
  @classes[name] = clazz
end

#add_unprocessed_attr(attr_config, clazz) ⇒ Object



117
118
119
120
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 117

def add_unprocessed_attr(attr_config, clazz)
  @unprocessed_attrs ||= []
  @unprocessed_attrs << AttrJob.new(attr_config, clazz)
end

#child_classes(hash, config) ⇒ Object



160
161
162
163
164
165
166
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 160

def child_classes(hash, config)
  config[:attrs].map do |attr|
    attr_type = attr[:opts][:as]
    type = attr_type.class == Array ? attr_type.first : attr_type
    type if hash.key? type
  end.compact
end

#create_cleanroom(root_class) ⇒ Object



76
77
78
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 76

def create_cleanroom(root_class)
  BaseCleanroom.new(root_class.new, self)
end

#deserialize_class(node, config) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 104

def deserialize_class(node, config)
  clazz = fetch(node.name) || new_roxml_class(config[:xml_name])
  config[:attrs].each do |attr|
    type_is_parent = node.parentage && node.parentage.any? {|n| n.name == attr[:opts][:as]}
    if type_is_parent
      add_unprocessed_attr attr, clazz
    else
      clazz.xml_accessor attr[:name], transform_accessor_opts(attr[:opts])
    end
  end
  clazz
end

#evaluate_file(path, root_class) ⇒ Object



56
57
58
59
60
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 56

def evaluate_file(path, root_class)
  cleanroom = RootCleanroom.new(fetch(root_class).new, self)
  cleanroom.evaluate_file path

end

#evaluate_raw(dsl, root_class, &block) ⇒ Object



62
63
64
65
66
67
68
69
70
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 62

def evaluate_raw(dsl, root_class, &block)
  cleanroom = RootCleanroom.new(fetch(root_class).new, self)
  if block_given?
    cleanroom.evaluate &block
  else
    cleanroom.evaluate dsl
  end

end

#fetch(class_name) ⇒ Object



48
49
50
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 48

def fetch(class_name)
  @classes[class_name]
end

#fetch_cleanroom(root_class) ⇒ Object



72
73
74
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 72

def fetch_cleanroom(root_class)
  BaseCleanroom.new(fetch(root_class).new, self)
end

#hash_to_tree(hash, root_name, processed = []) ⇒ Object



150
151
152
153
154
155
156
157
158
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 150

def hash_to_tree(hash, root_name, processed = [])
  node = Tree::TreeNode.new(root_name, hash[root_name])
  processed << root_name
  children = child_classes(hash, hash[root_name])
  children.each do |name|
    node << hash_to_tree(hash, name, processed) unless processed.include? name
  end
  node
end

#marshal_dumpObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 80

def marshal_dump
  classes = @classes.inject({}) do |hash, (name, clazz)|
    hash[name] = {xml_name: clazz.tag_name }
    hash[name][:attrs] = clazz.roxml_attrs.map do |accessor|
      type = accessor.sought_type.class == Class ?
        accessor.sought_type.class_name : accessor.sought_type
      from = accessor.sought_type == :attr ? "@#{accessor.name}" : accessor.name
      {
        name: accessor.accessor,
        opts: {
          as: accessor.array? ? [type] : type,
          from: from
        }
      }
    end
    hash
  end

  {
    root_classes: @root_classes,
    classes: classes
  }
end

#marshal_load(data) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 134

def marshal_load(data)
  initialize
  @root_classes.merge data[:root_classes]
  trees = @root_classes.map {|clazz| hash_to_tree data[:classes], clazz}
  trees.each do |tree|
    tree.postordered_each do |node|
      @classes[node.name] = deserialize_class(node, node.content)
    end
  end
  @unprocessed_attrs.each do |job|
    clazz = job.class
    config = job.config
    clazz.xml_accessor config[:name], transform_accessor_opts(config[:opts])
  end if @unprocessed_attrs
end

#populate(files, root_method = nil) ⇒ Object



18
19
20
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 18

def populate(files, root_method=nil)
  files.map {|f| populate_from_file f, root_method }
end

#populate_from_file(file, root_method = nil) ⇒ Object



22
23
24
25
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 22

def populate_from_file (file, root_method=nil)
  populate_raw File.read(file), root_method

end

#populate_raw(raw, root_method = nil) ⇒ Object

Parameters:

  • root_method (defaults to: nil)

    Symbol The method of the ROXML object to access its children



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 29

def populate_raw (raw, root_method = nil)
  builder = RoxmlBuilder.new (Nokogiri::XML(raw).root), @classes
  new_classes = builder.build_classes
  @root_classes << builder.root_class_name
  @classes.merge! new_classes
  if root_method
    roxml_root = fetch(builder.root_class_name).from_xml raw

    extractor = Extractor.new roxml_root.send(root_method), self

    new_objs = extractor.convert_roxml_objs
    subclasses = extractor.subclasses
    roxml_root.send("#{root_method}=", new_objs)
    builder = SexpDslBuilder.new [roxml_root], subclasses, self

    builder.write_full_dsl
  end
end

#serialize(path) ⇒ Object



169
170
171
172
173
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 169

def serialize(path)
  file = File.new path, 'w'
  Marshal.dump self, file
  file.close
end

#transform_accessor_opts(opts) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
# File 'lib/roundtrip_xml/dsl_runtime.rb', line 122

def transform_accessor_opts(opts)
  attr_type = opts[:as]
  is_array = attr_type.class == Array
  type = is_array ? attr_type.first : attr_type
  if is_array
    opts[:as] = [fetch(type)]
  else
    opts[:as] = fetch type
  end
  opts
end