xamplr-gen 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/COPYING +619 -0
- data/LICENSE +4 -0
- data/Makefile +11 -0
- data/README.md +33 -0
- data/Rakefile +66 -0
- data/VERSION +1 -0
- data/bin/xampl-gen +17 -0
- data/features/step_definitions/xamplr-gen_steps.rb +0 -0
- data/features/support/env.rb +6 -0
- data/features/xamplr-gen.feature +9 -0
- data/lib/xamplr-gen.rb +13 -0
- data/lib/xamplr-gen/.cvsignore +1 -0
- data/lib/xamplr-gen/graphml-out.rb +449 -0
- data/lib/xamplr-gen/my.gen.elements.xml +461 -0
- data/lib/xamplr-gen/simpleTemplate/danger.rx +4 -0
- data/lib/xamplr-gen/simpleTemplate/obsolete/input-c.r4 +35 -0
- data/lib/xamplr-gen/simpleTemplate/obsolete/play.r6.txt +12 -0
- data/lib/xamplr-gen/simpleTemplate/obsolete/play_more.r6.txt +20 -0
- data/lib/xamplr-gen/simpleTemplate/obsolete/test001.r5 +8 -0
- data/lib/xamplr-gen/simpleTemplate/obsolete/test002.r5 +13 -0
- data/lib/xamplr-gen/simpleTemplate/obsolete/test003.r5 +37 -0
- data/lib/xamplr-gen/simpleTemplate/old/r6.000.rb +122 -0
- data/lib/xamplr-gen/simpleTemplate/old/r6.001.rb +145 -0
- data/lib/xamplr-gen/simpleTemplate/play.r6 +12 -0
- data/lib/xamplr-gen/simpleTemplate/play_more.r6 +20 -0
- data/lib/xamplr-gen/simpleTemplate/play_noblanks.r6 +21 -0
- data/lib/xamplr-gen/simpleTemplate/playq.r6 +16 -0
- data/lib/xamplr-gen/simpleTemplate/r6.rb +87 -0
- data/lib/xamplr-gen/simpleTemplate/simple-template.rb +75 -0
- data/lib/xamplr-gen/templates/.cvsignore +3 -0
- data/lib/xamplr-gen/templates/child.template +47 -0
- data/lib/xamplr-gen/templates/child_indexed.template +89 -0
- data/lib/xamplr-gen/templates/child_modules.template +5 -0
- data/lib/xamplr-gen/templates/element_classes.template +11 -0
- data/lib/xamplr-gen/templates/element_data.template +283 -0
- data/lib/xamplr-gen/templates/element_empty.template +277 -0
- data/lib/xamplr-gen/templates/element_mixed.template +278 -0
- data/lib/xamplr-gen/templates/element_simple.template +277 -0
- data/lib/xamplr-gen/templates/package.template +38 -0
- data/lib/xamplr-gen/xampl-cl-gen.rb +89 -0
- data/lib/xamplr-gen/xampl-generator.rb +561 -0
- data/lib/xamplr-gen/xampl-hand-generated.rb +1534 -0
- data/lib/xamplr-gen/yuml-out.rb +127 -0
- data/licence.rb +17 -0
- data/test/helper.rb +10 -0
- data/test/test_xamplr-gen.rb +7 -0
- data/xamplr-gen.gemspec +98 -0
- metadata +124 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
|
2
|
+
class #{@element.class_name}
|
3
|
+
|
|
4
|
+
|if @element.persisted then
|
5
|
+
|
|
6
|
+
include Xampl::XamplPersistedObject
|
7
|
+
|
8
|
+
#supports class based over-ride of persister format
|
9
|
+
@@default_persister_format = nil
|
10
|
+
|
11
|
+
def default_persister_format
|
12
|
+
@@default_persister_format
|
13
|
+
end
|
14
|
+
def #{@element.class_name}.default_persister_format
|
15
|
+
@@default_persister_format
|
16
|
+
end
|
17
|
+
def #{@element.class_name}.set_default_persister_format(format)
|
18
|
+
@@default_persister_format = format
|
19
|
+
end
|
20
|
+
|
21
|
+
def #{@element.class_name}.find_by_query
|
22
|
+
things = Xampl.find_xampl do | q |
|
23
|
+
q.add_condition('class', :equals, self.name)
|
24
|
+
yield(q)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
|
29
|
+
|else
|
30
|
+
|
|
31
|
+
include Xampl::XamplObject
|
32
|
+
|
|
33
|
+
|end
|
34
|
+
|
|
35
|
+
include Xampl::XamplWithSimpleContent
|
36
|
+
|
37
|
+
@@tag = "#{@element.name}"
|
38
|
+
@@ns = "#{@element.namespace}"
|
39
|
+
@@ns_tag = "{#{@element.namespace}}#{@element.name}"
|
40
|
+
@@module_name = "#{@package_name}"
|
41
|
+
@@safe_name = "#{@package_name}_#{@element.attribute_name}"
|
42
|
+
@@attributes = [
|
43
|
+
|
|
44
|
+
|@element.attribute_child.each{ | attribute |
|
45
|
+
| if attribute.namespace then
|
46
|
+
|
|
47
|
+
[ :@#{attribute.name}, "#{attribute.name}", "#{attribute.namespace}" ],
|
48
|
+
|
|
49
|
+
| else
|
50
|
+
|
|
51
|
+
[ :@#{attribute.name}, "#{attribute.name}" ],
|
52
|
+
|
|
53
|
+
| end
|
54
|
+
|}
|
55
|
+
|
|
56
|
+
]
|
57
|
+
|
|
58
|
+
|@element.child_element_child.each{ | child_element |
|
59
|
+
| element_class_name = @lookup_element[child_element.name].class_name
|
60
|
+
| element_package = @lookup_element[child_element.name].package
|
61
|
+
|
|
62
|
+
include #{element_package}::#{element_class_name}AsChild
|
63
|
+
|
|
64
|
+
|}
|
65
|
+
|
|
66
|
+
|if @element.persisted then
|
67
|
+
|
|
68
|
+
|
69
|
+
def #{@element.class_name}.lookup(pid)
|
70
|
+
Xampl.lookup(#{@element.class_name}, pid)
|
71
|
+
end
|
72
|
+
|
73
|
+
def #{@element.class_name}.[](pid)
|
74
|
+
Xampl.lookup(#{@element.class_name}, pid)
|
75
|
+
end
|
76
|
+
|
|
77
|
+
|end
|
78
|
+
|
|
79
|
+
|@element.attribute_child.each{ | attribute |
|
80
|
+
| if attribute.name == @element.indexed_by_attr and @element.persisted then
|
81
|
+
|
|
82
|
+
|
83
|
+
def #{attribute.name}
|
84
|
+
@#{attribute.name}
|
85
|
+
end
|
86
|
+
|
87
|
+
def #{attribute.name}=(v)
|
88
|
+
accessed
|
89
|
+
# This is kind of optimistic, I think you are in trouble if you do this
|
90
|
+
Xampl.auto_uncache(self) if @#{attribute.name}
|
91
|
+
@#{attribute.name} = v
|
92
|
+
changed
|
93
|
+
Xampl.auto_cache(self) if v
|
94
|
+
end
|
95
|
+
|
|
96
|
+
| else
|
97
|
+
|
|
98
|
+
|
99
|
+
def #{attribute.name}
|
100
|
+
accessed
|
101
|
+
@#{attribute.name}
|
102
|
+
end
|
103
|
+
|
104
|
+
def #{attribute.name}=(v)
|
105
|
+
accessed
|
106
|
+
changed
|
107
|
+
@#{attribute.name} = v
|
108
|
+
end
|
109
|
+
|
|
110
|
+
| end
|
111
|
+
|}
|
112
|
+
|
|
113
|
+
| if @element.indexed_by_attr then
|
114
|
+
|
|
115
|
+
|
116
|
+
def initialize(index=nil)
|
117
|
+
@#{@element.indexed_by_attr} = index if index
|
118
|
+
super()
|
119
|
+
|
|
120
|
+
| else
|
121
|
+
|
|
122
|
+
|
123
|
+
def initialize
|
124
|
+
super
|
125
|
+
|
|
126
|
+
|end
|
127
|
+
|
|
128
|
+
|if 0 < @element.attribute_child.size then
|
129
|
+
|
|
130
|
+
|
131
|
+
|
|
132
|
+
|end
|
133
|
+
|
|
134
|
+
|@element.attribute_child.each{ | attribute |
|
135
|
+
|
|
136
|
+
@#{attribute.name} = nil if not defined? @#{attribute.name}
|
137
|
+
|
|
138
|
+
|}
|
139
|
+
|
|
140
|
+
|
141
|
+
init_xampl_object
|
142
|
+
|
|
143
|
+
|@element.child_element_child.each{ | child_element |
|
144
|
+
| element_attribute_name = @lookup_element[child_element.name].attribute_name
|
145
|
+
|
|
146
|
+
init_#{child_element.element_attribute_name}_as_child
|
147
|
+
|
|
148
|
+
|}
|
149
|
+
|
|
150
|
+
|
151
|
+
yield(self) if block_given?
|
152
|
+
init_hook
|
153
|
+
|
154
|
+
changed
|
155
|
+
end
|
156
|
+
|
157
|
+
def clear_non_persistent_index_attributes
|
158
|
+
|
|
159
|
+
|@element.attribute_child.each{ | attribute |
|
160
|
+
| unless attribute.name == @element.indexed_by_attr and @element.persisted then
|
161
|
+
|
|
162
|
+
@#{attribute.name} = nil
|
163
|
+
|
|
164
|
+
| end
|
165
|
+
|}
|
166
|
+
|
|
167
|
+
end
|
168
|
+
|
169
|
+
def append_to(other)
|
170
|
+
other.add_#{@element.attribute_name}(self)
|
171
|
+
end
|
172
|
+
|
173
|
+
|
|
174
|
+
|if @element.persisted then
|
175
|
+
|
|
176
|
+
def #{@element.class_name}.persisted?
|
177
|
+
return :#{@element.indexed_by_attr}
|
178
|
+
end
|
179
|
+
|
180
|
+
def persisted?
|
181
|
+
return :#{@element.indexed_by_attr}
|
182
|
+
end
|
183
|
+
|
184
|
+
|
|
185
|
+
|else
|
186
|
+
|
|
187
|
+
def #{@element.class_name}.persisted?
|
188
|
+
return nil
|
189
|
+
end
|
190
|
+
|
191
|
+
def persisted?
|
192
|
+
return nil
|
193
|
+
end
|
194
|
+
|
195
|
+
|
|
196
|
+
|end
|
197
|
+
|
|
198
|
+
def #{@element.class_name}.tag
|
199
|
+
@@tag
|
200
|
+
end
|
201
|
+
|
202
|
+
def #{@element.class_name}.ns
|
203
|
+
@@ns
|
204
|
+
end
|
205
|
+
|
206
|
+
def #{@element.class_name}.ns_tag
|
207
|
+
@@ns_tag
|
208
|
+
end
|
209
|
+
|
210
|
+
def #{@element.class_name}.safe_name
|
211
|
+
@@safe_name
|
212
|
+
end
|
213
|
+
|
214
|
+
def #{@element.class_name}.module_name
|
215
|
+
@@module_name
|
216
|
+
end
|
217
|
+
|
218
|
+
def tag
|
219
|
+
@@tag
|
220
|
+
end
|
221
|
+
|
222
|
+
def ns
|
223
|
+
@@ns
|
224
|
+
end
|
225
|
+
|
226
|
+
def ns_tag
|
227
|
+
@@ns_tag
|
228
|
+
end
|
229
|
+
|
230
|
+
def safe_name
|
231
|
+
@@safe_name
|
232
|
+
end
|
233
|
+
|
234
|
+
def module_name
|
235
|
+
@@module_name
|
236
|
+
end
|
237
|
+
|
238
|
+
def attributes
|
239
|
+
@@attributes
|
240
|
+
end
|
241
|
+
|
|
242
|
+
|if @element.indexed_by_attr
|
243
|
+
|
|
244
|
+
|
245
|
+
def indexed_by
|
246
|
+
:#{@element.indexed_by_attr}
|
247
|
+
end
|
248
|
+
|
249
|
+
def get_the_index
|
250
|
+
@#{@element.indexed_by_attr}
|
251
|
+
end
|
252
|
+
|
253
|
+
def set_the_index(index)
|
254
|
+
@#{@element.indexed_by_attr} = index
|
255
|
+
end
|
256
|
+
|
|
257
|
+
|end
|
258
|
+
|
|
259
|
+
|
260
|
+
def substitute_in_visit(visitor)
|
261
|
+
return visitor.substitute_in_visit_#{@element.attribute_name}(self) || self
|
262
|
+
end
|
263
|
+
|
264
|
+
def before_visit(visitor)
|
265
|
+
visitor.before_visit_#{@element.attribute_name}(self)
|
266
|
+
end
|
267
|
+
|
268
|
+
def visit(visitor)
|
269
|
+
visitor.visit_#{@element.attribute_name}(self)
|
270
|
+
end
|
271
|
+
|
272
|
+
def after_visit(visitor)
|
273
|
+
visitor.after_visit_#{@element.attribute_name}(self)
|
274
|
+
end
|
275
|
+
|
276
|
+
Xampl::FromXML::register(#{@element.class_name}::tag, #{@element.class_name}::ns_tag, #{@element.class_name})
|
277
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
|
2
|
+
| unless 'XamplAdHoc' == package_name
|
3
|
+
|
|
4
|
+
module #{package_name}
|
5
|
+
|
|
6
|
+
| end
|
7
|
+
|
|
8
|
+
|
9
|
+
require "xamplr"
|
10
|
+
include Xampl
|
11
|
+
|
12
|
+
|
|
13
|
+
| @required_packages.each_key{ | required_package_name |
|
14
|
+
|
|
15
|
+
require "#{required_package_name}"
|
16
|
+
|
|
17
|
+
| }
|
18
|
+
|
|
19
|
+
|
20
|
+
|
|
21
|
+
| if @options then
|
22
|
+
| @options.resolve_child.each{ | r |
|
23
|
+
| if r.namespace and (0 < r.namespace.length) and r.preferred_prefix and (0 < r.preferred_prefix.length) then
|
24
|
+
|
|
25
|
+
XamplObject.ns_preferred_prefix("#{r.namespace}", "#{r.preferred_prefix}")
|
26
|
+
|
|
27
|
+
| end
|
28
|
+
| }
|
29
|
+
| end
|
30
|
+
|
|
31
|
+
#{place}
|
32
|
+
|
|
33
|
+
| unless 'XamplAdHoc' == package_name
|
34
|
+
|
|
35
|
+
end
|
36
|
+
|
|
37
|
+
| end
|
38
|
+
|
|
@@ -0,0 +1,89 @@
|
|
1
|
+
|
2
|
+
#require 'xampl-generator'
|
3
|
+
|
4
|
+
include XamplGenerator
|
5
|
+
include Xampl
|
6
|
+
|
7
|
+
class ProjectGenerator
|
8
|
+
|
9
|
+
def directory
|
10
|
+
File.join(%w{ . xampl_generated_code })
|
11
|
+
end
|
12
|
+
|
13
|
+
def filenames
|
14
|
+
Dir.glob("./xml/**/*.xml")
|
15
|
+
end
|
16
|
+
|
17
|
+
def print_base_filename
|
18
|
+
File.join(%w{ . generated })
|
19
|
+
end
|
20
|
+
|
21
|
+
def print_options
|
22
|
+
# return an array containing any (or none) of:
|
23
|
+
# :schema -- a schema-like xml representation of the generated code
|
24
|
+
# :graphml -- a graphml file describing the class model (compatible with yEd)
|
25
|
+
# :yuml -- a yuml file that represents a simplified class model (compatible with yUML)
|
26
|
+
|
27
|
+
# [:schema, :graphml, :yuml]
|
28
|
+
[]
|
29
|
+
end
|
30
|
+
|
31
|
+
def print
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def persisted_attributes
|
36
|
+
%w{ pid }
|
37
|
+
end
|
38
|
+
|
39
|
+
def indexed_attributes
|
40
|
+
%w{ id }
|
41
|
+
end
|
42
|
+
|
43
|
+
def resolve_namespaces
|
44
|
+
# any array of arrays
|
45
|
+
# each sub-array:
|
46
|
+
# 0: a string or an array of strings, containing xml namespaces found in the example xml files
|
47
|
+
# an empty string is the default namespace
|
48
|
+
# 1: a ruby Module name (get the cases right)
|
49
|
+
# 2: a namespace prefix used when writing xml, optional. A generated prefix will be used otherwise.
|
50
|
+
[]
|
51
|
+
end
|
52
|
+
|
53
|
+
def generate
|
54
|
+
|
55
|
+
# Xampl.set_default_persister_kind(:simple)
|
56
|
+
Xampl.set_default_persister_kind(:in_memory)
|
57
|
+
# Xampl.set_default_persister_kind(:filesystem)
|
58
|
+
# Xampl.set_default_persister_kind(:tokyo_cabinet)
|
59
|
+
# Xampl.set_default_persister_format(:xml_format)
|
60
|
+
|
61
|
+
Xampl.transaction("project-generation") do
|
62
|
+
|
63
|
+
options = Options.new do | opts |
|
64
|
+
persisted_attributes.each do | pattr |
|
65
|
+
opts.new_index_attribute(pattr).persisted = true
|
66
|
+
end
|
67
|
+
|
68
|
+
indexed_attributes.each do | iattr |
|
69
|
+
opts.new_index_attribute(iattr)
|
70
|
+
end
|
71
|
+
|
72
|
+
resolve_namespaces.each do | namespace, ruby_module_name, output_ns_prefix |
|
73
|
+
opts.resolve(namespace, ruby_module_name, output_ns_prefix)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
generator = Generator.new('generator')
|
79
|
+
generator.go(:options => options,
|
80
|
+
:filenames => filenames,
|
81
|
+
:directory => directory)
|
82
|
+
|
83
|
+
puts generator.print_elements(print_base_filename, print_options)
|
84
|
+
|
85
|
+
Xampl.rollback
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
@@ -0,0 +1,561 @@
|
|
1
|
+
|
2
|
+
module XamplGenerator
|
3
|
+
|
4
|
+
class Attribute
|
5
|
+
attr_accessor :tag_name
|
6
|
+
end
|
7
|
+
|
8
|
+
class StandardGeneratorTemplates
|
9
|
+
include TemplateEngine
|
10
|
+
|
11
|
+
attr_accessor :element, :package_name, :place, :lookup_element, :options, :required_packages
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
super
|
15
|
+
@element = nil
|
16
|
+
@package_name = nil
|
17
|
+
@place = nil
|
18
|
+
@lookup_element = {}
|
19
|
+
@options = nil
|
20
|
+
@required_packages = {}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Generator
|
25
|
+
|
26
|
+
attr_accessor :elements_map, :options, :templates
|
27
|
+
|
28
|
+
@@standard_templates = [
|
29
|
+
"xamplr-gen/templates/child_modules.template",
|
30
|
+
"xamplr-gen/templates/child.template",
|
31
|
+
"xamplr-gen/templates/child_indexed.template",
|
32
|
+
"xamplr-gen/templates/element_classes.template",
|
33
|
+
"xamplr-gen/templates/element_data.template",
|
34
|
+
"xamplr-gen/templates/element_empty.template",
|
35
|
+
"xamplr-gen/templates/element_mixed.template",
|
36
|
+
"xamplr-gen/templates/element_simple.template",
|
37
|
+
"xamplr-gen/templates/package.template",
|
38
|
+
]
|
39
|
+
|
40
|
+
def initialize(options_in = nil, *predefined_elements)
|
41
|
+
@elements_map = {}
|
42
|
+
@xpp = nil
|
43
|
+
@templates = nil
|
44
|
+
@generated_package_map = nil
|
45
|
+
|
46
|
+
if options_in then
|
47
|
+
@options = options_in
|
48
|
+
else
|
49
|
+
@options = Xampl.make(Options) do |options|
|
50
|
+
options.new_index_attribute("id")
|
51
|
+
options.new_index_attribute("pid").persisted = true;
|
52
|
+
|
53
|
+
options.new_resolve do |resolver|
|
54
|
+
resolver.pkg = "XamplAdHoc"
|
55
|
+
resolver.namespace=""
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
predefined_elements.each do |elements|
|
61
|
+
throw :elements_need_a_pid unless elements.pid
|
62
|
+
@elements_map[elements.pid] = elements
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def start_element(parent)
|
67
|
+
name = @xpp.name
|
68
|
+
namespace = @xpp.namespace
|
69
|
+
namespace = "" unless namespace
|
70
|
+
is_empty = @xpp.emptyElement
|
71
|
+
|
72
|
+
nstag = "{{#{namespace}}}#{name}"
|
73
|
+
|
74
|
+
elements = @elements_map[namespace]
|
75
|
+
if nil == elements then
|
76
|
+
elements = Elements.new
|
77
|
+
@elements_map[namespace] = elements
|
78
|
+
end
|
79
|
+
|
80
|
+
element = elements.element_child[name]
|
81
|
+
if nil == element then
|
82
|
+
element = elements.new_element(name)
|
83
|
+
end
|
84
|
+
|
85
|
+
element.namespace = namespace
|
86
|
+
element.nstag = nstag
|
87
|
+
element.empty = is_empty
|
88
|
+
|
89
|
+
@xpp.attributeName.each_index do |i|
|
90
|
+
attribute = Attribute.new
|
91
|
+
attribute.name = @xpp.attributeName[i]
|
92
|
+
attribute.namespace = @xpp.attributeNamespace[i]
|
93
|
+
element.add_attribute(attribute)
|
94
|
+
end
|
95
|
+
|
96
|
+
if parent then
|
97
|
+
parent.new_child_element(nstag) do |ce|
|
98
|
+
ce.element_name = name
|
99
|
+
ce.namespace = namespace
|
100
|
+
end
|
101
|
+
end
|
102
|
+
return element
|
103
|
+
end
|
104
|
+
|
105
|
+
def parse_filename(filename)
|
106
|
+
@xpp = Xampl_PP.new
|
107
|
+
@xpp.input = File.new(filename)
|
108
|
+
parse
|
109
|
+
end
|
110
|
+
|
111
|
+
def parse_string(string)
|
112
|
+
@xpp = Xampl_PP.new
|
113
|
+
@xpp.input = string
|
114
|
+
parse
|
115
|
+
end
|
116
|
+
|
117
|
+
def parse
|
118
|
+
element_stack = []
|
119
|
+
current_element = nil
|
120
|
+
|
121
|
+
while not @xpp.endDocument? do
|
122
|
+
case @xpp.nextEvent
|
123
|
+
when Xampl_PP::START_ELEMENT
|
124
|
+
element_stack.push current_element unless nil == current_element
|
125
|
+
current_element = start_element(current_element)
|
126
|
+
when Xampl_PP::END_ELEMENT
|
127
|
+
current_element = element_stack.pop
|
128
|
+
when Xampl_PP::TEXT,
|
129
|
+
Xampl_PP::CDATA_SECTION,
|
130
|
+
Xampl_PP::ENTITY_REF
|
131
|
+
if current_element then
|
132
|
+
text = @xpp.text
|
133
|
+
if (nil != @xpp.text) then
|
134
|
+
text = text.strip
|
135
|
+
current_element.found_text_content if 0 < text.size
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def comprehend_from_files(filenames)
|
143
|
+
filenames.each do |filename|
|
144
|
+
puts "comprehend file #{filename}"
|
145
|
+
parse_filename(filename)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def comprehend_from_strings(strings)
|
150
|
+
strings.each do |string|
|
151
|
+
parse_string(string)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def analyse
|
156
|
+
namespace_package_map = {}
|
157
|
+
namespace_prefix_map = {}
|
158
|
+
options.resolve_child.each do |resolve|
|
159
|
+
namespace_package_map[resolve.namespace] = resolve.pkg
|
160
|
+
end
|
161
|
+
|
162
|
+
@elements_map.each do |ns, elements|
|
163
|
+
package = namespace_package_map[ns]
|
164
|
+
|
165
|
+
elements.element_child.each do |element|
|
166
|
+
element.package = package
|
167
|
+
element.analyse(options)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
@required_packages = {}
|
172
|
+
@elements_map.each do |ns, elements|
|
173
|
+
package = namespace_package_map[ns]
|
174
|
+
|
175
|
+
required = @required_packages[package]
|
176
|
+
unless required then
|
177
|
+
required = {}
|
178
|
+
@required_packages[package] = required
|
179
|
+
end
|
180
|
+
|
181
|
+
elements.element_child.each do |element|
|
182
|
+
element.child_element_child.each do |child_element|
|
183
|
+
celement = child_element.find_element(@elements_map)
|
184
|
+
#required[celement.package] = celement.package
|
185
|
+
unless package == celement.package then
|
186
|
+
required[celement.package] = celement.package
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def ensure_templates
|
194
|
+
return if @templates
|
195
|
+
|
196
|
+
@templates = StandardGeneratorTemplates.new
|
197
|
+
@templates.compile_scripts(@@standard_templates)
|
198
|
+
end
|
199
|
+
|
200
|
+
def find_place(directory_name, package)
|
201
|
+
#puts "find_place:: package: #{package}"
|
202
|
+
|
203
|
+
@generated_package_map = {} unless @generated_package_map
|
204
|
+
|
205
|
+
place = @generated_package_map[package]
|
206
|
+
if nil == place then
|
207
|
+
place = ""
|
208
|
+
@generated_package_map[package] = place
|
209
|
+
end
|
210
|
+
return place
|
211
|
+
end
|
212
|
+
|
213
|
+
def generate(directory_name, params={:verbose => false}, &eval_context)
|
214
|
+
if directory_name then
|
215
|
+
FileUtils.mkdir_p(directory_name) unless File.exist?(directory_name)
|
216
|
+
end
|
217
|
+
|
218
|
+
ensure_templates
|
219
|
+
|
220
|
+
module_names = Set.new
|
221
|
+
@elements_map.each do |ns, elements|
|
222
|
+
elements.element_child.each do |element|
|
223
|
+
module_names << element.package
|
224
|
+
break
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
lookup_element = {}
|
229
|
+
@elements_map.each do |ns, elements|
|
230
|
+
elements.element_child.each do |element|
|
231
|
+
lookup_element[element.nstag] = element
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
@templates.lookup_element = lookup_element
|
236
|
+
|
237
|
+
@elements_map.each do |ns, elements|
|
238
|
+
elements.element_child.each do |element|
|
239
|
+
place = find_place(directory_name, element.package)
|
240
|
+
|
241
|
+
@templates.element = element
|
242
|
+
@templates.package_name = element.package
|
243
|
+
|
244
|
+
if element.class_name == element.package then
|
245
|
+
puts "ERROR: Class #{ element.package } is in a module with the same name -- this NOT going to work"
|
246
|
+
elsif module_names.member?(element.class_name)
|
247
|
+
puts "WARNING: a Class and a Module have the same name (#{ element.package }) -- this is highly unlikely to work"
|
248
|
+
end
|
249
|
+
|
250
|
+
@templates.child_modules(place)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
@elements_map.each do |ns, elements|
|
255
|
+
elements.element_child.each do |element|
|
256
|
+
place = find_place(directory_name, element.package)
|
257
|
+
|
258
|
+
@templates.element = element
|
259
|
+
@templates.package_name = element.package
|
260
|
+
|
261
|
+
@templates.element_classes(place)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
@generated_package_map.each do |package_name, definition|
|
266
|
+
package_name = "XamplAdHoc" unless package_name
|
267
|
+
|
268
|
+
@templates.element = nil
|
269
|
+
@templates.package_name = package_name
|
270
|
+
@templates.options = @options
|
271
|
+
|
272
|
+
@templates.required_packages = @required_packages[package_name] || {}
|
273
|
+
|
274
|
+
@templates.place = definition
|
275
|
+
|
276
|
+
package_definition = @templates.package
|
277
|
+
|
278
|
+
if directory_name then
|
279
|
+
output_filename = File.join(directory_name, "#{package_name}.rb")
|
280
|
+
puts "WRITE TO FILE: #{output_filename}"
|
281
|
+
#puts package_definition
|
282
|
+
File.open(output_filename, "w") do |file|
|
283
|
+
file.puts package_definition
|
284
|
+
end
|
285
|
+
end
|
286
|
+
if block_given? then
|
287
|
+
package_name = "XamplAdHoc" unless package_name
|
288
|
+
puts "EVALUATE: #{package_name}"
|
289
|
+
eval_context.call(package_definition, package_name)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
report_elements if params[:verbose]
|
294
|
+
end
|
295
|
+
|
296
|
+
def report_elements
|
297
|
+
@elements_map.each_value do |elements|
|
298
|
+
puts elements.pp_xml
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def print_elements(base_filename, print_options=nil)
|
303
|
+
return unless base_filename
|
304
|
+
return unless print_options
|
305
|
+
return if 0 == print_options.size
|
306
|
+
|
307
|
+
root = Elements.new
|
308
|
+
@elements_map.each_value do |elements|
|
309
|
+
elements.element_child.each do |element|
|
310
|
+
root.children << element
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
print_options.each do | print_option |
|
315
|
+
case print_option
|
316
|
+
when :schema then
|
317
|
+
File.open("#{base_filename}.xml", "w") do |out|
|
318
|
+
root.pp_xml(out)
|
319
|
+
end
|
320
|
+
when :graphml then
|
321
|
+
graphml_out = GraphMLOut.new(@elements_map)
|
322
|
+
graphml_out.write_graph_ml(base_filename)
|
323
|
+
when :yuml then
|
324
|
+
yuml_out = YUMLOut.new(@elements_map)
|
325
|
+
yuml_out.write_yuml(base_filename)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def go(args, &eval_context)
|
331
|
+
options = args[:options]
|
332
|
+
if options then
|
333
|
+
@options = options
|
334
|
+
end
|
335
|
+
|
336
|
+
strings = args[:strings]
|
337
|
+
if strings then
|
338
|
+
comprehend_from_strings(strings)
|
339
|
+
end
|
340
|
+
|
341
|
+
filenames = args[:filenames]
|
342
|
+
if filenames then
|
343
|
+
comprehend_from_files(filenames)
|
344
|
+
end
|
345
|
+
|
346
|
+
directory = args[:directory]
|
347
|
+
if directory then
|
348
|
+
generate_to_directory(directory, args)
|
349
|
+
else
|
350
|
+
generate_and_eval(args) do |module_definition, name|
|
351
|
+
yield(module_definition, name)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def generate_to_directory(directory_name, params={:verbose => false})
|
357
|
+
analyse
|
358
|
+
return generate(directory_name, params)
|
359
|
+
end
|
360
|
+
|
361
|
+
def generate_and_eval(params={:verbose => false}, &eval_context)
|
362
|
+
analyse
|
363
|
+
return generate(nil, params, &eval_context)
|
364
|
+
end
|
365
|
+
|
366
|
+
def Generator.choose_names(original_name, attr_prefix="_", attr_suffix="_")
|
367
|
+
|
368
|
+
# name = original_name.gsub(/[^a-zA-Z_]+/, "_")
|
369
|
+
|
370
|
+
# NOTE (2009-04-16) -- if tag starts with a number, prefix it with an 'x'
|
371
|
+
name = original_name.sub(/^([0-9])/) { | m | "x" + m }
|
372
|
+
name = name.gsub(/[^a-zA-Z0-9_]+/, "_")
|
373
|
+
|
374
|
+
|
375
|
+
attr_name = name.gsub(/[A-Z]+/, "_\\&")
|
376
|
+
attr_name.gsub!(/__+/, "_")
|
377
|
+
attr_name = attr_name[1..-1] if "_"[0] == attr_name[0]
|
378
|
+
attr_name.downcase!
|
379
|
+
|
380
|
+
name.gsub!(/[A-Z]/, "_\\&")
|
381
|
+
name.gsub!(/__+/, "_")
|
382
|
+
class_name = ""
|
383
|
+
#name.each("_") do |chunk|
|
384
|
+
name.split("_").each do |chunk|
|
385
|
+
class_name << chunk.capitalize
|
386
|
+
end
|
387
|
+
class_name.gsub!("_", "")
|
388
|
+
|
389
|
+
return class_name, attr_name
|
390
|
+
end
|
391
|
+
|
392
|
+
def print_stats
|
393
|
+
count = 0
|
394
|
+
@elements_map.each do |ns, elements|
|
395
|
+
count += elements.element_child.size
|
396
|
+
printf("namespace: %s, element: %d\n", ns, elements.element_child.size)
|
397
|
+
end
|
398
|
+
printf("counts of:: namespace: %d, element: %d\n", @elements_map.size, count)
|
399
|
+
@elements_map.each do |ns, elements|
|
400
|
+
puts elements.pp_xml
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
class Options
|
406
|
+
def resolve(namespace, pkg="XamplAdHoc", preferred_prefix=nil)
|
407
|
+
if (namespace.kind_of?(Array)) then
|
408
|
+
namespace.each do |ns, prefix|
|
409
|
+
self.new_resolve do |resolver|
|
410
|
+
resolver.pkg = pkg
|
411
|
+
resolver.namespace = ns
|
412
|
+
resolver.preferred_prefix = prefix
|
413
|
+
end
|
414
|
+
end
|
415
|
+
else
|
416
|
+
self.new_resolve do |resolver|
|
417
|
+
resolver.pkg = pkg
|
418
|
+
resolver.namespace = namespace
|
419
|
+
resolver.preferred_prefix = preferred_prefix
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
class ChildElement
|
426
|
+
def find_element(map)
|
427
|
+
elements = map[self.namespace]
|
428
|
+
return elements.element[self.element_name]
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
class Element
|
433
|
+
def found_text_content
|
434
|
+
self.has_content = true
|
435
|
+
end
|
436
|
+
|
437
|
+
def analyse(options)
|
438
|
+
is_empty, is_simple, is_data, is_mixed = false
|
439
|
+
|
440
|
+
class_name, attribute_name = Generator.choose_names(@name)
|
441
|
+
@class_name = class_name unless @class_name
|
442
|
+
@attribute_name = attribute_name unless @attribute_name
|
443
|
+
|
444
|
+
no_children = (0 == @child_element_child.size)
|
445
|
+
|
446
|
+
unless @kind then
|
447
|
+
if no_children then
|
448
|
+
is_simple = @has_content
|
449
|
+
is_empty = !is_simple
|
450
|
+
else
|
451
|
+
is_mixed = @has_content
|
452
|
+
is_data = !@has_content
|
453
|
+
end
|
454
|
+
|
455
|
+
# this isn't a very strong piece of information, can't do much about it.
|
456
|
+
#attribute_like = ((0 == @attribute_child.size) and is_simple)
|
457
|
+
|
458
|
+
if is_empty then
|
459
|
+
@kind = "empty"
|
460
|
+
elsif is_simple then
|
461
|
+
@kind = "simple"
|
462
|
+
elsif is_data then
|
463
|
+
@kind = "data"
|
464
|
+
elsif is_mixed then
|
465
|
+
@kind = "mixed"
|
466
|
+
else
|
467
|
+
throw "no kind determined" # this should be impossible
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
unless self.indexed_by_attr then
|
472
|
+
attribute_child.each do |attribute|
|
473
|
+
aname_orig = attribute.name
|
474
|
+
class_name, aname = Generator.choose_names(aname_orig)
|
475
|
+
attribute.name = aname
|
476
|
+
attribute.tag_name = aname_orig
|
477
|
+
|
478
|
+
options.index_attribute_child.each do |iattr|
|
479
|
+
if aname == iattr.name then
|
480
|
+
self.indexed_by_attr = aname
|
481
|
+
self.persisted = iattr.persisted
|
482
|
+
break
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
if self.persisted then
|
488
|
+
attribute = Attribute.new
|
489
|
+
attribute.name = 'scheduled_for_deletion_at'
|
490
|
+
attribute.tag_name = 'scheduled-for-deletion-at'
|
491
|
+
attribute.namespace = nil
|
492
|
+
self.add_attribute(attribute)
|
493
|
+
end
|
494
|
+
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def XamplGenerator.from_command_line(options=nil)
|
500
|
+
opts = GetoptLong.new(
|
501
|
+
["--options", "-o", GetoptLong::REQUIRED_ARGUMENT],
|
502
|
+
["--elements", "-e", GetoptLong::REQUIRED_ARGUMENT],
|
503
|
+
["--gen:options", "-O", GetoptLong::OPTIONAL_ARGUMENT],
|
504
|
+
["--gen:elements", "-E", GetoptLong::OPTIONAL_ARGUMENT],
|
505
|
+
["--directory", "-d", GetoptLong::REQUIRED_ARGUMENT],
|
506
|
+
["--help", "-h", GetoptLong::NO_ARGUMENT],
|
507
|
+
["--version", "-v", GetoptLong::NO_ARGUMENT]
|
508
|
+
)
|
509
|
+
|
510
|
+
write_options = nil
|
511
|
+
write_elements = nil
|
512
|
+
directory = File.join(".", "tmp")
|
513
|
+
|
514
|
+
opts.each do |opt, arg|
|
515
|
+
case opt
|
516
|
+
when "--help" then
|
517
|
+
puts "--help, -h :: this help message"
|
518
|
+
puts "--options, -o :: xml file seting the generation options"
|
519
|
+
puts "--elements, -e :: xml file providing a hint 'schema' (very optional)"
|
520
|
+
puts "--gen:options, -O :: write an xml file describing the options used (default gen-options.xml)"
|
521
|
+
puts "--gen:elements, -E :: write an xml file describing the 'schema' (default gen-elements.xml)"
|
522
|
+
puts "--directory, -o :: where to write the generated files (default #{directory})"
|
523
|
+
puts "--version, -o :: what version of xampl is this?"
|
524
|
+
exit
|
525
|
+
when "--version" then
|
526
|
+
puts "version 0.0.0"
|
527
|
+
exit
|
528
|
+
when "--directory"
|
529
|
+
directory = arg
|
530
|
+
when "--options"
|
531
|
+
puts "sorry, cannot read options yet"
|
532
|
+
when "--elements"
|
533
|
+
puts "sorry, cannot read elements yet"
|
534
|
+
when "--gen:options"
|
535
|
+
write_options = (arg and (0 < arg.length)) ? arg : "gen-options.xml"
|
536
|
+
when "--gen:elements"
|
537
|
+
write_elements = (arg and (0 < arg.length)) ? arg : "gen-elements.xml"
|
538
|
+
else
|
539
|
+
puts " #{opt} #{arg}"
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
puts "write options to: #{write_options}" if write_options
|
544
|
+
puts "write elements to: #{write_elements}" if write_elements
|
545
|
+
puts "write generated code to: #{directory}" if directory
|
546
|
+
|
547
|
+
generator = Generator.new(options)
|
548
|
+
|
549
|
+
filenames = []
|
550
|
+
ARGV.each do |name|
|
551
|
+
filenames << name
|
552
|
+
end
|
553
|
+
|
554
|
+
if 0 < filenames.length then
|
555
|
+
generator.comprehend_from_files(filenames)
|
556
|
+
generator.generate_to_directory(directory)
|
557
|
+
|
558
|
+
generator.print_elements(write_elements) if write_elements
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|