scaffold_parser 0.5.0 → 0.6.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/lib/scaffold_parser.rb +29 -25
  4. data/lib/scaffold_parser/scaffolders/xsd.rb +140 -33
  5. data/lib/scaffold_parser/scaffolders/xsd/parser.rb +37 -106
  6. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/all.rb +29 -0
  7. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/at_method.rb +38 -0
  8. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/base_method.rb +36 -0
  9. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/blank.rb +73 -0
  10. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/choice.rb +38 -0
  11. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/class_inherit.rb +17 -0
  12. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/complex_type.rb +46 -0
  13. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/elements.rb +60 -0
  14. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/extension.rb +30 -0
  15. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/import.rb +15 -0
  16. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/include.rb +15 -0
  17. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/klass.rb +121 -0
  18. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/list_method.rb +86 -0
  19. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/module.rb +67 -0
  20. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/module_include.rb +37 -0
  21. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/proxy_list_method.rb +53 -0
  22. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/requires.rb +19 -0
  23. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/sequence.rb +50 -0
  24. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/submodel_method.rb +59 -0
  25. data/lib/scaffold_parser/scaffolders/xsd/parser/handlers/utils.rb +39 -0
  26. data/lib/scaffold_parser/scaffolders/xsd/parser/module_template.rb +35 -0
  27. data/lib/scaffold_parser/scaffolders/xsd/parser/stack.rb +50 -0
  28. data/scaffold_parser.gemspec +2 -1
  29. metadata +39 -6
  30. data/lib/scaffold_parser/file_patches.rb +0 -13
  31. data/lib/scaffold_parser/nokogiri_patches.rb +0 -194
  32. data/lib/scaffold_parser/scaffolders/xsd/builder.rb +0 -105
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 017e23477330b9cf2841a422f3d2d60b71d4288c
4
- data.tar.gz: 3698f8522b0687d180a01ee817e0da43d4cb5e8f
3
+ metadata.gz: a86da6f57bcf43be3e59f2a47531005113ada9ff
4
+ data.tar.gz: e29b1f9dbea6e921666a001bc51c9213db18e15d
5
5
  SHA512:
6
- metadata.gz: 2d064e3292e12916fafcc8c307814b09f4cb38b0c4455471777ae8c1a5046166fa1a9962669393f1422cedb8bc327c863c7422e8f4e810b3418de1b7d07949f6
7
- data.tar.gz: c5709d9484f8cb1de6d04eb02137712b576b9cf753228491297af1864331090deb3f0b9bcc34872a02153cfb5c4a382fbca65485c94dc4c858333e5feb509a2c
6
+ metadata.gz: 664fc7cc63285c13ba2b620bc13224f9752a1887ed33c1ac6ee7e20984aecee83b0fdf7b6f21a948b00162e7b47e7931f935f841accb529ed4c8057dcb33480f
7
+ data.tar.gz: 0d469c89f076255eefad50e3290ab8dc1b59cf11976f7ff25418e1957fda6a1306d3480e355fba259dab6a43b04e255a034d804af9a683b0e18b2376fb1fcba5
data/Gemfile CHANGED
@@ -4,3 +4,5 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in scaffold_parser.gemspec
6
6
  gemspec
7
+
8
+ gem 'xsd_model', path: '/home/masa331/code/ruby/xsd_model/'
@@ -1,31 +1,16 @@
1
- require 'nokogiri'
1
+ require 'xsd_model'
2
2
  require 'active_support/all'
3
- require 'scaffold_parser/nokogiri_patches'
4
- require 'scaffold_parser/file_patches'
5
3
  require 'scaffold_parser/scaffolders/xsd'
6
4
 
7
- Nokogiri::XML::Element.include ScaffoldParser::NokogiriPatches::Element
8
- Nokogiri::XML::Document.include ScaffoldParser::NokogiriPatches::Document
9
- StringIO.include ScaffoldParser::FilePatches
10
-
11
5
  module ScaffoldParser
12
6
  def self.scaffold(path, options = {})
13
- unless Dir.exists?('./tmp/')
14
- Dir.mkdir('./tmp/')
15
- puts './tmp/ directory created'
16
- end
7
+ ensure_dir_exists('./tmp/')
8
+ ensure_dir_exists('./tmp/builders')
9
+ ensure_dir_exists('./tmp/builders/groups')
10
+ ensure_dir_exists('./tmp/parsers')
11
+ ensure_dir_exists('./tmp/parsers/groups')
17
12
 
18
- unless Dir.exists?('./tmp/builders')
19
- Dir.mkdir('./tmp/builders')
20
- puts './tmp/builders directory created'
21
- end
22
-
23
- unless Dir.exists?('./tmp/parsers')
24
- Dir.mkdir('./tmp/parsers')
25
- puts './tmp/parsers directory created'
26
- end
27
-
28
- scaffold_to_string(path, options).each do |path, content|
13
+ scaffold_to_string(File.read(path), options).each do |path, content|
29
14
  complete_path = path.prepend('./tmp/')
30
15
 
31
16
  puts "Writing out #{complete_path}" if options[:verbose]
@@ -34,9 +19,28 @@ module ScaffoldParser
34
19
  end
35
20
  end
36
21
 
37
- def self.scaffold_to_string(path, options = {})
38
- doc = Nokogiri::XML(File.open(path))
22
+ def self.scaffold_to_string(schema, options = {})
23
+ parse_options = { collect_only: [:element,
24
+ :complex_type,
25
+ :sequence,
26
+ :all,
27
+ :choice,
28
+ :schema,
29
+ :include,
30
+ :import,
31
+ :group,
32
+ :extension] }
33
+ doc = XsdModel.parse(schema, parse_options)
34
+
35
+ Scaffolders::XSD.call(doc, options, parse_options)
36
+ end
37
+
38
+ private
39
39
 
40
- Scaffolders::XSD.call(doc, options)
40
+ def self.ensure_dir_exists(path)
41
+ unless Dir.exists?(path)
42
+ Dir.mkdir(path)
43
+ puts "#{path} directory created"
44
+ end
41
45
  end
42
46
  end
@@ -1,57 +1,59 @@
1
1
  require 'scaffold_parser/scaffolders/xsd/parser'
2
- require 'scaffold_parser/scaffolders/xsd/builder'
2
+ require 'scaffold_parser/scaffolders/xsd/parser/handlers/utils'
3
3
 
4
4
  module ScaffoldParser
5
5
  module Scaffolders
6
6
  class XSD
7
- def self.call(doc, options)
8
- self.new(doc, options).call
7
+ include Parser::Handlers::Utils
8
+
9
+ def self.call(doc, options, parse_options = {})
10
+ self.new(doc, options, parse_options).call
9
11
  end
10
12
 
11
- def initialize(doc, options)
13
+ def initialize(doc, options, parse_options = {})
12
14
  @doc = doc
13
15
  @options = options
16
+ @parse_options = parse_options
14
17
  end
15
18
 
16
19
  def call
17
- puts "Starting collectiong elements to scaffold" if @options[:verbose]
20
+ all = [@doc.schema] + @doc.schema.collect_included_schemas(@parse_options) + @doc.schema.collect_imported_schemas(@parse_options)
18
21
 
19
- unscaffolded_elements = collect_unscaffolded_subelements(@doc) + @doc.submodel_nodes
22
+ classes = Parser.call(all, @options)
20
23
 
21
- puts "Collected #{unscaffolded_elements.size} elements to scaffold" if @options[:verbose]
24
+ classes.each do |klass|
25
+ klass.methods = klass.methods.map do |meth|
26
+ if meth.is_a?(Parser::Handlers::SubmodelMethod) && !classes.map(&:name).include?(meth.submodel_class)
27
+ meth.to_at_method
28
+ else
29
+ meth
30
+ end
31
+ end
32
+ end
22
33
 
23
- code = unscaffolded_elements.flat_map do |element|
24
- [Parser.call(element.definition, @options), Builder.call(element.definition, @options)]
34
+ classes.each do |klass|
35
+ klass.namespace = @options[:namespace]
25
36
  end
26
37
 
27
- code.push ['parsers/base_parser.rb', base_parser_template]
28
- code.push ['builders/base_builder.rb', base_builder_template]
38
+ classes.flat_map do |class_template|
39
+ [["parsers/#{class_template.name.underscore}.rb", class_template.to_s],
40
+ ["builders/#{class_template.name.underscore}.rb", class_template.to_builder_s],
41
+ ["parsers/base_parser.rb", wrap_in_namespace(base_parser_template, @options[:namespace])],
42
+ ["builders/base_builder.rb", wrap_in_namespace(base_builder_template, @options[:namespace])],
43
+ ["requires.rb", create_requires_template(classes)],
44
+ ["hash_with_attrs.rb", wrap_in_namespace(hash_with_attrs_template, @options[:namespace])],
45
+ ["mega.rb", wrap_in_namespace(mega_template, @options[:namespace])]
46
+ ]
47
+ end
29
48
  end
30
49
 
31
50
  private
32
51
 
33
- def collect_unscaffolded_subelements(node, collected = [])
34
- subelements = node.definition.submodel_nodes.to_a + node.definition.array_nodes.map(&:list_element)
35
- .reject(&:xs_type?)
36
- .reject { |node| collected.include?(node.to_class_name) }
37
-
38
- subelements.each do |element|
39
- if collected.none? { |c| c.to_class_name == element.to_class_name }
40
- collected << element
41
-
42
- puts "Collected #{element.to_name} element" if @options[:verbose]
43
-
44
- collect_unscaffolded_subelements(element, collected)
45
- end
46
- end
47
-
48
- collected
49
- end
50
-
51
52
  def base_parser_template
52
53
  <<~TEMPLATE
53
54
  module Parsers
54
55
  module BaseParser
56
+ include Mega
55
57
  EMPTY_ARRAY = []
56
58
 
57
59
  attr_accessor :raw
@@ -95,6 +97,12 @@ module ScaffoldParser
95
97
  klass.new(element)
96
98
  end
97
99
  end
100
+
101
+ def to_h_with_attrs
102
+ hash = HashWithAttributes.new({}, attributes)
103
+
104
+ hash
105
+ end
98
106
  end
99
107
  end
100
108
  TEMPLATE
@@ -104,18 +112,25 @@ module ScaffoldParser
104
112
  <<~TEMPLATE
105
113
  module Builders
106
114
  module BaseBuilder
107
- attr_accessor :name, :data
115
+ attr_accessor :name, :data, :options
108
116
 
109
- def initialize(name, data = {})
117
+ def initialize(name, data = {}, options = {})
110
118
  @name = name
111
119
  @data = data || {}
120
+ @options = options || {}
112
121
  end
113
122
 
114
123
  def to_xml
115
- doc = Ox::Document.new(version: '1.0')
124
+ encoding = options[:encoding]
125
+
126
+ doc_options = { version: '1.0' }
127
+ doc_options[:encoding] = encoding if encoding
128
+ doc = Ox::Document.new(doc_options)
116
129
  doc << builder
117
130
 
118
- Ox.dump(doc, with_xml: true)
131
+ dump_options = { with_xml: true }
132
+ dump_options[:encoding] = encoding if encoding
133
+ Ox.dump(doc, dump_options)
119
134
  end
120
135
 
121
136
  def build_element(name, content)
@@ -135,6 +150,98 @@ module ScaffoldParser
135
150
  end
136
151
  TEMPLATE
137
152
  end
153
+
154
+ def hash_with_attrs_template
155
+ <<~TEMPLATE
156
+ class HashWithAttributes
157
+ def initialize(hash, attributes = nil)
158
+ @hash = hash
159
+ @attributes = attributes if attributes
160
+ end
161
+
162
+ def value
163
+ @hash
164
+ end
165
+
166
+ def attributes
167
+ @attributes ||= {}
168
+ end
169
+
170
+ def attributes=(attributes)
171
+ @attributes = attributes
172
+ end
173
+
174
+ def ==(other)
175
+ if other.respond_to?(:value) && other.respond_to?(:attributes)
176
+ value == other.value && other.attributes == attributes
177
+ else
178
+ value == other
179
+ end
180
+ end
181
+
182
+ def merge(other)
183
+ merged_hash = value.merge other.value
184
+ merged_attrs = attributes.merge other.attributes
185
+
186
+ self.class.new(merged_hash, merged_attrs)
187
+ end
188
+
189
+ def key?(key)
190
+ value.key? key
191
+ end
192
+
193
+ def [](key)
194
+ value[key]
195
+ end
196
+
197
+ def []=(key, key_value)
198
+ value[key] = key_value
199
+ end
200
+
201
+ def dig(*attrs)
202
+ value.dig(*attrs)
203
+ end
204
+ end
205
+ TEMPLATE
206
+ end
207
+
208
+ def mega_template
209
+ <<~TEMPLATE
210
+ module Mega
211
+ def mega
212
+ called_from = caller_locations[0].label
213
+ included_modules = (self.class.included_modules - Class.included_modules - [Mega])
214
+ included_modules.map { |m| m.instance_method(called_from).bind(self).call }
215
+ end
216
+ end
217
+ TEMPLATE
218
+ end
219
+
220
+ def create_requires_template(classes)
221
+ modules = classes.select { |cl| cl.is_a? Parser::Handlers::Module }
222
+ classes = classes.select { |cl| cl.is_a? Parser::Handlers::Klass }
223
+ with_inheritance, others = classes.partition { |klass| klass.inherit_from }
224
+
225
+ requires = ['parsers/base_parser', 'builders/base_builder']
226
+ modules.each do |klass|
227
+ requires << "parsers/#{klass.name.underscore}"
228
+ requires << "builders/#{klass.name.underscore}"
229
+ end
230
+ others.each do |klass|
231
+ requires << "parsers/#{klass.name.underscore}"
232
+ requires << "builders/#{klass.name.underscore}"
233
+ end
234
+ with_inheritance.each do |klass|
235
+ requires << "parsers/#{klass.name.underscore}"
236
+ requires << "builders/#{klass.name.underscore}"
237
+ end
238
+
239
+ if @options[:namespace]
240
+ requires = requires.map { |r| r.prepend("#{@options[:namespace].underscore}/") }
241
+ end
242
+
243
+ requires.map { |r| "require '#{r}'" }.join("\n")
244
+ end
138
245
  end
139
246
  end
140
247
  end
@@ -1,122 +1,53 @@
1
+ require 'scaffold_parser/scaffolders/xsd/parser/stack'
2
+ require 'scaffold_parser/scaffolders/xsd/parser/handlers/requires'
3
+
1
4
  module ScaffoldParser
2
5
  module Scaffolders
3
6
  class XSD
4
7
  class Parser
5
- attr_reader :node
8
+ attr_reader :xsds
6
9
 
7
- def self.call(node, options)
8
- self.new(node, options).call
10
+ def self.call(xsds, options)
11
+ self.new(xsds, options).call
9
12
  end
10
13
 
11
- def initialize(node, options)
12
- @node = node
14
+ def initialize(xsds, options)
15
+ @xsds = xsds
13
16
  @options = options
14
17
  end
15
18
 
16
- def call
17
- puts "Scaffolding parser for #{node.to_name}" if @options[:verbose]
18
-
19
- f = StringIO.new
20
- f.indent = true if @options[:namespace]
21
-
22
- f.puts "require '#{namespaced('parsers/base_parser')}'"
23
- node.submodel_nodes.map { |n| namespaced(n.to_class_name.underscore.prepend('parsers/')) }.uniq.each { |n| f.puts "require '#{n}'" }
24
- node.array_nodes.reject { |l| l.list_element.xs_type? }.each { |n| f.puts "require '#{namespaced(n.list_element.to_class_name.underscore.prepend('parsers/'))}'" }
25
- f.puts
26
-
27
- f.puts "module #{@options[:namespace]}" if @options[:namespace]
28
- f.putsi "module Parsers"
29
- f.putsi " class #{node.to_class_name}"
30
- f.putsi " include BaseParser"
31
-
32
- node.value_nodes.each do |method|
33
- f.puts
34
-
35
- method_name = method.to_name.underscore
36
- at = method.to_name
37
-
38
- f.putsi " def #{method_name}"
39
- f.putsi " at '#{at}'"
40
- f.putsi " end"
41
- end
42
-
43
- node.submodel_nodes.each do |method|
44
- f.puts
45
-
46
- klass = method.to_class_name
47
- method_name = method.to_name.underscore
48
- at = method.to_name
49
-
50
- f.putsi " def #{method_name}"
51
- f.putsi " submodel_at(#{klass}, '#{at}')"
52
- f.putsi " end"
53
- end
54
-
55
- node.array_nodes.reject { |l| l.list_element.xs_type? }.each do |method|
56
- f.puts
57
-
58
- list_element_klass = method.list_element_klass
59
- method_name = method.to_name.underscore
60
- list_element_at = method.list_element_at.map { |e| "'#{e}'" }.join(', ')
19
+ STACK = Stack.instance
61
20
 
62
- f.putsi " def #{method_name}"
63
- f.putsi " array_of_at(#{list_element_klass}, [#{list_element_at}])"
64
- f.putsi " end"
65
- end
66
-
67
- node.array_nodes.select { |l| l.list_element.xs_type? }.each do |method|
68
- f.puts
69
-
70
- list_element_klass = method.list_element_klass
71
- method_name = method.to_name.underscore
72
- list_element_at = method.list_element_at.map { |e| "'#{e}'" }.join(', ')
73
-
74
- f.putsi " def #{method_name}"
75
- f.putsi " array_of_at(String, [#{list_element_at}])"
76
- f.putsi " end"
77
- end
78
-
79
- ### to_h method
80
- lines = []
81
- node.value_nodes.each do |node|
82
- lines << "hash[:#{node.to_name.underscore}] = #{node.to_name.underscore} if has? '#{node.to_name}'"
83
- end
84
-
85
- node.submodel_nodes.each do |node|
86
- lines << "hash[:#{node.to_name.underscore}] = #{node.to_name.underscore}.to_h_with_attrs if has? '#{node.to_name}'"
87
- end
88
- node.array_nodes.reject { |l| l.list_element.xs_type? }.each do |node|
89
- lines << "hash[:#{node.to_name.underscore}] = #{node.to_name.underscore}.map(&:to_h_with_attrs) if has? '#{node.to_name}'"
90
- end
91
- node.array_nodes.select { |l| l.list_element.xs_type? }.each do |node|
92
- lines << "hash[:#{node.to_name.underscore}] = #{node.to_name.underscore} if has? '#{node.to_name}'"
93
- end
94
- if lines.any?
95
- f.puts
96
-
97
- f.putsi " def to_h_with_attrs"
98
- f.putsi " hash = HashWithAttributes.new({}, attributes)"
99
- f.puts
100
-
101
- lines.each do |line|
102
- f.putsi " #{line}"
21
+ def call
22
+ STACK.clear
23
+
24
+ classes =
25
+ xsds.map do |xsd|
26
+ if @options[:verbose]
27
+ puts "\n\nScaffolding schema which defines:\n#{xsd.children.map { |c| c.name }.compact}\n"
28
+ end
29
+
30
+ xsd.reverse_traverse do |element, children_result|
31
+ handler =
32
+ if children_result.empty?
33
+ Handlers::Blank.new
34
+ elsif children_result.one?
35
+ children_result.first
36
+ else
37
+ Handlers::Elements.new(children_result)
38
+ end
39
+
40
+ if @options[:verbose]
41
+ current_handler = handler.class.to_s.demodulize
42
+ childrens = (handler.instance_variable_get('@elements') || []).map { |child| child.class.to_s.demodulize }
43
+ puts "#{current_handler}#{childrens}##{element.element_name}"
44
+ end
45
+
46
+ handler.send(element.element_name, element)
47
+ end
103
48
  end
104
- f.puts
105
-
106
- f.putsi " hash"
107
- f.putsi " end"
108
- end
109
- f.putsi " end"
110
- f.putsi "end"
111
- f.puts "end" if @options[:namespace]
112
-
113
- ["parsers/#{node.to_class_name.underscore}.rb", f.string.strip]
114
- end
115
-
116
- private
117
49
 
118
- def namespaced(path)
119
- [@options[:namespace]&.underscore, path].compact.join('/')
50
+ classes = STACK.to_a
120
51
  end
121
52
  end
122
53
  end