command_builder_generator 0.0.1
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/lib/command_builder_generator.rb +1 -0
- data/lib/command_builder_generator/code_generator.rb +82 -0
- data/lib/command_builder_generator/command.rb +50 -0
- data/lib/command_builder_generator/command_argument.rb +30 -0
- data/lib/command_builder_generator/command_code_names.rb +77 -0
- data/lib/command_builder_generator/command_definition.rb +25 -0
- data/lib/command_builder_generator/fragment.rb +35 -0
- data/lib/command_builder_generator/lib/argument_formatter.rb +22 -0
- data/lib/command_builder_generator/lib/argument_formatters/array_argument_formatter.rb +22 -0
- data/lib/command_builder_generator/lib/argument_formatters/hash_argument_formatter.rb +27 -0
- data/lib/command_builder_generator/lib/argument_formatters/string_argument_formatter.rb +17 -0
- data/lib/command_builder_generator/lib/command_base.rb +20 -0
- data/lib/command_builder_generator/node.rb +65 -0
- data/lib/command_builder_generator/node_code_generator.rb +99 -0
- data/lib/command_builder_generator/node_code_names.rb +31 -0
- data/lib/command_builder_generator/ruby_code_writer.rb +61 -0
- data/lib/command_builder_generator/string_extensions.rb +35 -0
- data/lib/command_builder_generator/version.rb +45 -0
- metadata +95 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_relative 'command_builder_generator/code_generator'
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'erb'
|
|
2
|
+
require_relative 'command_definition'
|
|
3
|
+
require_relative 'command_code_names'
|
|
4
|
+
require_relative 'ruby_code_writer'
|
|
5
|
+
require_relative 'node_code_generator'
|
|
6
|
+
require 'fileutils'
|
|
7
|
+
|
|
8
|
+
module CommandBuilderGenerator
|
|
9
|
+
class CodeGenerator
|
|
10
|
+
|
|
11
|
+
def initialize(definition_file)
|
|
12
|
+
@definition_file = definition_file
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def execute
|
|
16
|
+
puts "Processing: #{File.basename @definition_file}"
|
|
17
|
+
d = CommandDefinition.new File.new(@definition_file)
|
|
18
|
+
d.versions.each { |v| process_version d.command, v }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def process_version(command, version)
|
|
24
|
+
generate_command_module command, version
|
|
25
|
+
generate_version_module command, version
|
|
26
|
+
FileUtils.cp_r File.expand_path(File.dirname(__FILE__) + '/lib'), Dir.getwd
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def generate_command_module(command, version)
|
|
30
|
+
code_names = CommandCodeNames.new command, version
|
|
31
|
+
|
|
32
|
+
model = {
|
|
33
|
+
module_name: code_names.command_module_name,
|
|
34
|
+
factory_method_name: code_names.command_factory_method_name,
|
|
35
|
+
command_name: command.command_name
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
template_file = File.expand_path(File.dirname(__FILE__) + '/templates/command_module.erb')
|
|
39
|
+
result_file = "#{code_names.command_factory_method_name}.rb"
|
|
40
|
+
sub_template model, template_file, result_file
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def generate_version_module(command, version)
|
|
44
|
+
code_names = CommandCodeNames.new command, version
|
|
45
|
+
|
|
46
|
+
model = {
|
|
47
|
+
command_factory_method_signature: code_names.command_factory_method_signature,
|
|
48
|
+
version_factory_method_signature: code_names.version_factory_method_signature,
|
|
49
|
+
create_method_signature: code_names.create_method_signature,
|
|
50
|
+
create_method_call: code_names.create_method_call,
|
|
51
|
+
command_initializer_call: code_names.command_initializer_call,
|
|
52
|
+
command_module_name: code_names.command_module_name,
|
|
53
|
+
version_module_name: code_names.version_module_name,
|
|
54
|
+
version: version,
|
|
55
|
+
command_class: generate_command_class(command),
|
|
56
|
+
factory_method_name: code_names.command_factory_method_name,
|
|
57
|
+
command_factory_method_call: code_names.command_factory_method_call,
|
|
58
|
+
command_name: command.command_name
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
template_file = File.expand_path(File.dirname(__FILE__) + '/templates/version_module.erb')
|
|
62
|
+
result_file = File.join "#{code_names.version_factory_method_name}.rb"
|
|
63
|
+
sub_template model, template_file, result_file
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def sub_template(model, template_file, result_file)
|
|
67
|
+
template = ERB.new File.read(template_file)
|
|
68
|
+
result = template.result(binding)
|
|
69
|
+
File.open(result_file, 'w') { |f| f.write result }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def generate_command_class(command)
|
|
73
|
+
stream = StringIO.new
|
|
74
|
+
writer = RubyCodeWriter.new stream
|
|
75
|
+
writer.indent = 3
|
|
76
|
+
node_code_generator = NodeCodeGenerator.new command, command, writer
|
|
77
|
+
node_code_generator.render
|
|
78
|
+
stream.string
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require_relative 'string_extensions'
|
|
3
|
+
require_relative 'node'
|
|
4
|
+
|
|
5
|
+
module CommandBuilderGenerator
|
|
6
|
+
class Command < Node
|
|
7
|
+
|
|
8
|
+
attr_reader :command_name
|
|
9
|
+
|
|
10
|
+
def initialize(command_def)
|
|
11
|
+
hash = Command.command_hash command_def
|
|
12
|
+
command_text = hash.keys[0]
|
|
13
|
+
command_name = Command.command_name command_text
|
|
14
|
+
node_def = command_text[command_name.length, command_text.length]
|
|
15
|
+
super node_def
|
|
16
|
+
Command.process_array hash.values[0], self
|
|
17
|
+
@command_name = command_name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def node_name
|
|
21
|
+
@node_name ||= node_alias || @command_name
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def Command.command_name(command_text)
|
|
27
|
+
command_text[/^([-\.\w]+)/, 1]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def Command.command_hash(command_text)
|
|
31
|
+
yaml = command_text.split(String::NEW_LINE).map { |l| l.gsub(/^( *)(\S.+)$/, '\1- "\2":') }.join String::NEW_LINE
|
|
32
|
+
array = YAML.load yaml
|
|
33
|
+
array[0]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def Command.process_array(array, parent_node=nil)
|
|
37
|
+
array ||= []
|
|
38
|
+
array.each { |hash| Command.process_hash hash, parent_node }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def Command.process_hash(hash, parent_node)
|
|
42
|
+
hash.each_pair do |node_text, child_nodes|
|
|
43
|
+
node = Node.new " #{node_text}"
|
|
44
|
+
parent_node.child_nodes << node
|
|
45
|
+
process_array child_nodes, node
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module CommandBuilderGenerator
|
|
2
|
+
class CommandArgument
|
|
3
|
+
|
|
4
|
+
def initialize(arg_text, required=true)
|
|
5
|
+
@arg_text = arg_text
|
|
6
|
+
@required = required
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def arg_name
|
|
10
|
+
@arg_name ||= @arg_text[/<(\w+)/, 1]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def key_value_separator
|
|
14
|
+
@key_value_separator ||= @arg_text[/(\W)\W>/, 1]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def delimiter
|
|
18
|
+
@delimiter ||= @arg_text[/(\W)>/, 1]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def required?
|
|
22
|
+
@required
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def optional?
|
|
26
|
+
!required?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require_relative 'string_extensions'
|
|
2
|
+
|
|
3
|
+
module CommandBuilderGenerator
|
|
4
|
+
class CommandCodeNames
|
|
5
|
+
|
|
6
|
+
def initialize(command, version=nil)
|
|
7
|
+
@command = command
|
|
8
|
+
@compact_version = version.to_s.gsub('.', '_')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def command_module_name
|
|
12
|
+
@command.node_name.camelcase
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def version_module_name
|
|
16
|
+
"V#{@compact_version}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def command_factory_method_name
|
|
20
|
+
@command.node_name.downcase.snakecase
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def command_factory_method_signature
|
|
24
|
+
format_method command_factory_method_name, factory_method_args
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def version_factory_method_name
|
|
28
|
+
"#{command_factory_method_name}_#{@compact_version.downcase.snakecase}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def version_factory_method_signature
|
|
32
|
+
format_method version_factory_method_name, factory_method_args
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def create_method_signature
|
|
36
|
+
format_method 'self.create', factory_method_args
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def create_method_call
|
|
40
|
+
format_method "CommandBuilder::#{command_module_name}::#{version_module_name}.create", initializer_values
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def command_factory_method_call
|
|
44
|
+
format_method command_factory_method_name, initializer_values
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def command_initializer_call
|
|
48
|
+
format_method "#{class_name}.new", initializer_values
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def format_method(method_name, method_args)
|
|
54
|
+
method_args = method_args.join ', '
|
|
55
|
+
result = method_name
|
|
56
|
+
result << "(#{method_args})" unless method_args.empty?
|
|
57
|
+
result
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def factory_method_args
|
|
61
|
+
@command.args.map do |arg|
|
|
62
|
+
arg_name = arg.arg_name.snakecase
|
|
63
|
+
arg_name << '=nil' if arg.optional?
|
|
64
|
+
arg_name
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def initializer_values
|
|
69
|
+
@command.args.map { |arg| arg.arg_name.snakecase }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def class_name
|
|
73
|
+
@command.node_name.camelcase
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require_relative 'command'
|
|
2
|
+
require_relative 'version'
|
|
3
|
+
require_relative 'string_extensions'
|
|
4
|
+
|
|
5
|
+
module CommandBuilderGenerator
|
|
6
|
+
class CommandDefinition
|
|
7
|
+
|
|
8
|
+
attr_reader :versions, :command
|
|
9
|
+
|
|
10
|
+
def initialize(stream)
|
|
11
|
+
s = stream.read
|
|
12
|
+
@versions = parse_versions s.first_line
|
|
13
|
+
@command = Command.new s.strip_first_line
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def parse_versions(line)
|
|
19
|
+
versions = line.split_and_strip ','
|
|
20
|
+
versions.each { |v| Version.new v }
|
|
21
|
+
versions
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require_relative 'command_argument'
|
|
2
|
+
|
|
3
|
+
module CommandBuilderGenerator
|
|
4
|
+
class Fragment
|
|
5
|
+
|
|
6
|
+
def initialize(fragment_def)
|
|
7
|
+
@fragment_def = fragment_def
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def fragment_text
|
|
11
|
+
@fragment_text ||= optional? ? @fragment_def[1, @fragment_def.length - 2] : @fragment_def
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def required?
|
|
15
|
+
!optional?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def optional?
|
|
19
|
+
@optional ||= @fragment_def.start_with?('[') && @fragment_def.end_with?(']')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def args
|
|
23
|
+
@args ||= fragment_text.scan(/<.+?>/).flatten.map { |m| CommandArgument.new m, required? }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def arg_names
|
|
27
|
+
@arg_names ||= args.map { |a| a.arg_name }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def has_args?
|
|
31
|
+
@has_args ||= !args.empty?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require_relative 'argument_formatters/array_argument_formatter'
|
|
2
|
+
require_relative 'argument_formatters/hash_argument_formatter'
|
|
3
|
+
require_relative 'argument_formatters/string_argument_formatter'
|
|
4
|
+
|
|
5
|
+
module CommandBuilder
|
|
6
|
+
class ArgumentFormatter
|
|
7
|
+
|
|
8
|
+
def format(argument, options={})
|
|
9
|
+
|
|
10
|
+
formatter = case
|
|
11
|
+
when argument.kind_of?(Array)
|
|
12
|
+
ArrayArgumentFormatter.new options[:delimiter]
|
|
13
|
+
when argument.kind_of?(Hash)
|
|
14
|
+
HashArgumentFormatter.new options[:delimiter], options[:key_value_separator]
|
|
15
|
+
else
|
|
16
|
+
StringArgumentFormatter.new
|
|
17
|
+
end
|
|
18
|
+
formatter.format argument
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require_relative 'string_argument_formatter'
|
|
2
|
+
|
|
3
|
+
module CommandBuilder
|
|
4
|
+
class ArrayArgumentFormatter
|
|
5
|
+
|
|
6
|
+
def initialize(delimiter)
|
|
7
|
+
@delimiter = delimiter
|
|
8
|
+
@string_argument_formatter = StringArgumentFormatter.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def format(argument)
|
|
12
|
+
argument.map { |v| format_string_argument v }.join @delimiter
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def format_string_argument(s)
|
|
18
|
+
@string_argument_formatter.format s
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require_relative 'string_argument_formatter'
|
|
2
|
+
|
|
3
|
+
module CommandBuilder
|
|
4
|
+
class HashArgumentFormatter
|
|
5
|
+
|
|
6
|
+
def initialize(delimiter, key_value_separator)
|
|
7
|
+
@delimiter = delimiter
|
|
8
|
+
@key_value_separator = key_value_separator
|
|
9
|
+
@string_argument_formatter = StringArgumentFormatter.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def format(argument)
|
|
13
|
+
argument.map { |k, v| format_pair k, v }.join @delimiter
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def format_pair(k, v)
|
|
19
|
+
format_string_argument(k) + @key_value_separator + format_string_argument(v)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def format_string_argument(s)
|
|
23
|
+
@string_argument_formatter.format s
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require_relative 'argument_formatter'
|
|
2
|
+
|
|
3
|
+
module CommandBuilder
|
|
4
|
+
class CommandBase
|
|
5
|
+
|
|
6
|
+
attr_reader :passwords
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
puts 'aaaa'
|
|
10
|
+
@s = StringIO.new
|
|
11
|
+
@f = ArgumentFormatter.new
|
|
12
|
+
@passwords = []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_s
|
|
16
|
+
@s.string
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require_relative 'fragment'
|
|
2
|
+
|
|
3
|
+
module CommandBuilderGenerator
|
|
4
|
+
class Node
|
|
5
|
+
|
|
6
|
+
def initialize(node_def)
|
|
7
|
+
@node_def = node_def
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def child_nodes
|
|
11
|
+
@child_nodes ||= []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def branch?
|
|
15
|
+
!child_nodes.empty?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def leaf?
|
|
19
|
+
child_nodes.empty?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def node_name
|
|
23
|
+
@node_name ||= node_alias || (starts_with_arg? ? first_arg_name : words_preceding_args)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def fragments
|
|
27
|
+
@fragments ||= @node_def.gsub(/ \(.+?\)/, '').gsub(']', ']|').gsub('[', '|[').split('|').compact.map { |f| Fragment.new f }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def args
|
|
31
|
+
required_args + optional_args
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
def required_args
|
|
37
|
+
select_args { |a| a.required? }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def optional_args
|
|
41
|
+
select_args { |a| a.optional? }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def starts_with_arg?
|
|
45
|
+
words_preceding_args.empty?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def first_arg_name
|
|
49
|
+
@node_def[/<(.+?)>/, 1]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def words_preceding_args
|
|
53
|
+
@node_def.gsub(/<.*/, '').gsub(/\W/, ' ').strip
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def node_alias
|
|
57
|
+
@node_def[/\((.+?)\)/, 1]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def select_args
|
|
61
|
+
fragments.map { |f| f.args.map { |a| a if yield a } }.flatten.compact
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
require_relative 'string_extensions'
|
|
2
|
+
require_relative 'node'
|
|
3
|
+
require_relative 'node_code_names'
|
|
4
|
+
|
|
5
|
+
module CommandBuilderGenerator
|
|
6
|
+
class NodeCodeGenerator
|
|
7
|
+
|
|
8
|
+
def initialize(node, command, writer)
|
|
9
|
+
@node = node
|
|
10
|
+
@command = command
|
|
11
|
+
@writer = writer
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render
|
|
15
|
+
render_branch_node if @node.branch?
|
|
16
|
+
render_leaf_node if @node.leaf?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def render_method
|
|
20
|
+
@writer.write_method node_code_names.method_name, node_code_names.method_args do
|
|
21
|
+
if @node.branch?
|
|
22
|
+
render_branch_node_method_body
|
|
23
|
+
else
|
|
24
|
+
render_leaf_node_method_body
|
|
25
|
+
@writer.write_line '@s << yield if block_given?'
|
|
26
|
+
@writer.write_line 'self'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def render_branch_node
|
|
34
|
+
@writer.write_class node_code_names.class_name, 'CommandBase' do
|
|
35
|
+
render_constructor
|
|
36
|
+
@node.child_nodes.each do |n|
|
|
37
|
+
generator = NodeCodeGenerator.new n, @command, @writer
|
|
38
|
+
generator.render_method
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
render_child_nodes
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def render_leaf_node
|
|
45
|
+
render_child_nodes
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def render_child_nodes
|
|
49
|
+
@node.child_nodes.each do |n|
|
|
50
|
+
generator = NodeCodeGenerator.new n, @command, @writer
|
|
51
|
+
generator.render
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def render_constructor
|
|
56
|
+
@writer.write_method 'initialize', node_code_names.method_args do
|
|
57
|
+
@writer.write_line 'super()'
|
|
58
|
+
render_leaf_node_method_body
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def render_branch_node_method_body
|
|
63
|
+
args = node_code_names.initializer_values
|
|
64
|
+
@writer.write_line "#{node_code_names.class_name}.new #{args.join ', '}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def render_leaf_node_method_body
|
|
68
|
+
@node.fragments.each { |f| write_append_statement f }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def write_append_statement(fragment)
|
|
72
|
+
return if fragment.fragment_text.empty?
|
|
73
|
+
unless_condition = fragment.arg_names.map { |a| "#{a.snakecase}.nil?" }.join ' or '
|
|
74
|
+
statement = "@s << #{append_arg fragment}"
|
|
75
|
+
statement << " unless #{unless_condition}" if fragment.optional? and fragment.has_args?
|
|
76
|
+
@writer.write_line statement
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def append_arg(fragment)
|
|
80
|
+
value = fragment.fragment_text.gsub(/<.+?>/) do |m|
|
|
81
|
+
arg = CommandArgument.new m
|
|
82
|
+
is_password = arg.arg_name.downcase.include? 'password'
|
|
83
|
+
|
|
84
|
+
if is_password
|
|
85
|
+
"\#{format_password #{arg.arg_name.snakecase}}"
|
|
86
|
+
else
|
|
87
|
+
format_args = [arg.arg_name.snakecase, [arg.delimiter, arg.key_value_separator].compact.map { |v| "'#{v}'" }].flatten
|
|
88
|
+
"\#{@f.format #{format_args.join ', '}}"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
value.include?('#{') ? %Q["#{value}"] : "'#{value}'"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def node_code_names
|
|
95
|
+
@node_code_names ||= NodeCodeNames.new @node
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require_relative 'string_extensions'
|
|
2
|
+
|
|
3
|
+
module CommandBuilderGenerator
|
|
4
|
+
class NodeCodeNames
|
|
5
|
+
|
|
6
|
+
def initialize(node)
|
|
7
|
+
@node = node
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def class_name
|
|
11
|
+
@node.node_name.camelcase
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def method_name
|
|
15
|
+
@node.node_name.snakecase
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def method_args
|
|
19
|
+
@node.args.map do |arg|
|
|
20
|
+
arg_name = arg.arg_name.snakecase
|
|
21
|
+
arg_name << '=nil' if arg.optional?
|
|
22
|
+
arg_name
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initializer_values
|
|
27
|
+
@node.args.map { |arg| arg.arg_name.snakecase }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module CommandBuilderGenerator
|
|
2
|
+
class RubyCodeWriter
|
|
3
|
+
|
|
4
|
+
INDENT_SPACES = 2
|
|
5
|
+
|
|
6
|
+
attr_accessor :indent
|
|
7
|
+
|
|
8
|
+
def initialize(stream)
|
|
9
|
+
@stream = stream
|
|
10
|
+
@indent = 0
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def indent
|
|
14
|
+
@indent += 1
|
|
15
|
+
if block_given?
|
|
16
|
+
yield
|
|
17
|
+
dedent
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def dedent
|
|
22
|
+
@indent -= 1
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def write(code)
|
|
26
|
+
@stream.print code
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def write_line(line='')
|
|
30
|
+
@stream.puts line.rjust(line.length + @indent * INDENT_SPACES, ' ')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def write_block(line)
|
|
34
|
+
write_line line
|
|
35
|
+
indent
|
|
36
|
+
yield
|
|
37
|
+
dedent
|
|
38
|
+
write_line 'end'
|
|
39
|
+
line
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def write_module(module_name)
|
|
43
|
+
write_block("module #{module_name}") { yield }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def write_class(class_name, base_class_name=nil)
|
|
47
|
+
line = "class #{class_name}"
|
|
48
|
+
line << " < #{base_class_name}" if base_class_name
|
|
49
|
+
write_block(line) { yield }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def write_method(method_name, *args)
|
|
53
|
+
args = [args].flatten
|
|
54
|
+
line = "def #{method_name}"
|
|
55
|
+
line << "(#{args.join ', '})" unless args.empty?
|
|
56
|
+
write_block(line) { yield }
|
|
57
|
+
@stream.puts
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
class String
|
|
3
|
+
|
|
4
|
+
NEW_LINE = "\n"
|
|
5
|
+
|
|
6
|
+
def camelcase
|
|
7
|
+
words.join
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def snakecase
|
|
11
|
+
words.join('_').downcase
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def first_line
|
|
15
|
+
match(/^.*$/)[0]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def strip_first_line
|
|
19
|
+
first_line_index = self.index NEW_LINE
|
|
20
|
+
return '' unless first_line_index
|
|
21
|
+
self[first_line_index+1..self.length-1]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def split_and_strip(pattern)
|
|
25
|
+
split(pattern).map { |s| s.strip }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def words
|
|
31
|
+
result = self =~ /^[A-Z]+$/ ? downcase : self
|
|
32
|
+
result.gsub(/[\W_]/, ' ').gsub(/[A-Z*]/, ' \0').split(' ').map { |s| s.capitalize }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module CommandBuilderGenerator
|
|
2
|
+
class Version
|
|
3
|
+
|
|
4
|
+
VERSION_REGEX = '(?:\d+\.)+(?:\d+)'
|
|
5
|
+
DELIMITER = '.'
|
|
6
|
+
|
|
7
|
+
attr_accessor :version
|
|
8
|
+
|
|
9
|
+
def initialize(version)
|
|
10
|
+
raise "#{version} is not a valid version." unless Version.is_valid? version
|
|
11
|
+
@version = version
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def compact
|
|
15
|
+
first 2, '_'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def first(count, delimiter=DELIMITER)
|
|
19
|
+
to_a.first(count).join(delimiter)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_s
|
|
23
|
+
@version
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_a
|
|
27
|
+
@version.split DELIMITER
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.match(value)
|
|
31
|
+
exp = Regexp.new VERSION_REGEX
|
|
32
|
+
version = value.scan(exp)[0]
|
|
33
|
+
return unless version
|
|
34
|
+
Version.new(version)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def self.is_valid?(version)
|
|
40
|
+
exp = Regexp.new "^#{VERSION_REGEX}$"
|
|
41
|
+
version.scan(exp)[0] != nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: command_builder_generator
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Matthew Riley
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-10-12 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: mocha
|
|
16
|
+
requirement: &70225892059240 !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0.14'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: *70225892059240
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: rake
|
|
27
|
+
requirement: &70225892058760 !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - ~>
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '10.1'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: *70225892058760
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: test-unit
|
|
38
|
+
requirement: &70225892058300 !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - ~>
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '2.5'
|
|
44
|
+
type: :development
|
|
45
|
+
prerelease: false
|
|
46
|
+
version_requirements: *70225892058300
|
|
47
|
+
description: Description
|
|
48
|
+
email: matthew@matthewriley.name
|
|
49
|
+
executables: []
|
|
50
|
+
extensions: []
|
|
51
|
+
extra_rdoc_files: []
|
|
52
|
+
files:
|
|
53
|
+
- lib/command_builder_generator/code_generator.rb
|
|
54
|
+
- lib/command_builder_generator/command.rb
|
|
55
|
+
- lib/command_builder_generator/command_argument.rb
|
|
56
|
+
- lib/command_builder_generator/command_code_names.rb
|
|
57
|
+
- lib/command_builder_generator/command_definition.rb
|
|
58
|
+
- lib/command_builder_generator/fragment.rb
|
|
59
|
+
- lib/command_builder_generator/lib/argument_formatter.rb
|
|
60
|
+
- lib/command_builder_generator/lib/argument_formatters/array_argument_formatter.rb
|
|
61
|
+
- lib/command_builder_generator/lib/argument_formatters/hash_argument_formatter.rb
|
|
62
|
+
- lib/command_builder_generator/lib/argument_formatters/string_argument_formatter.rb
|
|
63
|
+
- lib/command_builder_generator/lib/command_base.rb
|
|
64
|
+
- lib/command_builder_generator/node.rb
|
|
65
|
+
- lib/command_builder_generator/node_code_generator.rb
|
|
66
|
+
- lib/command_builder_generator/node_code_names.rb
|
|
67
|
+
- lib/command_builder_generator/ruby_code_writer.rb
|
|
68
|
+
- lib/command_builder_generator/string_extensions.rb
|
|
69
|
+
- lib/command_builder_generator/version.rb
|
|
70
|
+
- lib/command_builder_generator.rb
|
|
71
|
+
homepage:
|
|
72
|
+
licenses: []
|
|
73
|
+
post_install_message:
|
|
74
|
+
rdoc_options: []
|
|
75
|
+
require_paths:
|
|
76
|
+
- lib
|
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
|
+
none: false
|
|
79
|
+
requirements:
|
|
80
|
+
- - ! '>='
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
|
+
none: false
|
|
85
|
+
requirements:
|
|
86
|
+
- - ! '>='
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
requirements: []
|
|
90
|
+
rubyforge_project:
|
|
91
|
+
rubygems_version: 1.8.15
|
|
92
|
+
signing_key:
|
|
93
|
+
specification_version: 3
|
|
94
|
+
summary: Summary
|
|
95
|
+
test_files: []
|