scaffold_parser 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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