synvert-core 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -4
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile +0 -3
  5. data/Guardfile +0 -9
  6. data/README.md +30 -12
  7. data/Rakefile +1 -15
  8. data/lib/synvert/core/engine/erb.rb +1 -1
  9. data/lib/synvert/core/engine.rb +1 -1
  10. data/lib/synvert/core/node_ext.rb +0 -466
  11. data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +20 -17
  12. data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +1 -1
  13. data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +1 -1
  14. data/lib/synvert/core/rewriter/instance.rb +83 -133
  15. data/lib/synvert/core/rewriter/scope/query_scope.rb +2 -2
  16. data/lib/synvert/core/rewriter/scope/within_scope.rb +4 -4
  17. data/lib/synvert/core/rewriter.rb +0 -10
  18. data/lib/synvert/core/version.rb +1 -1
  19. data/lib/synvert/core.rb +4 -6
  20. data/spec/synvert/core/engine/erb_spec.rb +3 -3
  21. data/spec/synvert/core/node_ext_spec.rb +0 -795
  22. data/spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb +21 -1
  23. data/spec/synvert/core/rewriter/instance_spec.rb +47 -115
  24. data/spec/synvert/core/rewriter/scope/goto_scope_spec.rb +1 -4
  25. data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +1 -4
  26. data/spec/synvert/core/rewriter/scope/within_scope_spec.rb +1 -4
  27. data/synvert-core-ruby.gemspec +4 -2
  28. metadata +44 -61
  29. data/lib/synvert/core/array_ext.rb +0 -48
  30. data/lib/synvert/core/node_query/compiler/array.rb +0 -34
  31. data/lib/synvert/core/node_query/compiler/attribute.rb +0 -39
  32. data/lib/synvert/core/node_query/compiler/attribute_list.rb +0 -24
  33. data/lib/synvert/core/node_query/compiler/basic_selector.rb +0 -28
  34. data/lib/synvert/core/node_query/compiler/boolean.rb +0 -23
  35. data/lib/synvert/core/node_query/compiler/comparable.rb +0 -86
  36. data/lib/synvert/core/node_query/compiler/dynamic_attribute.rb +0 -51
  37. data/lib/synvert/core/node_query/compiler/expression.rb +0 -41
  38. data/lib/synvert/core/node_query/compiler/float.rb +0 -23
  39. data/lib/synvert/core/node_query/compiler/identifier.rb +0 -41
  40. data/lib/synvert/core/node_query/compiler/integer.rb +0 -23
  41. data/lib/synvert/core/node_query/compiler/invalid_operator_error.rb +0 -7
  42. data/lib/synvert/core/node_query/compiler/nil.rb +0 -23
  43. data/lib/synvert/core/node_query/compiler/parse_error.rb +0 -7
  44. data/lib/synvert/core/node_query/compiler/regexp.rb +0 -37
  45. data/lib/synvert/core/node_query/compiler/selector.rb +0 -113
  46. data/lib/synvert/core/node_query/compiler/string.rb +0 -23
  47. data/lib/synvert/core/node_query/compiler/symbol.rb +0 -23
  48. data/lib/synvert/core/node_query/compiler.rb +0 -25
  49. data/lib/synvert/core/node_query/lexer.rex +0 -99
  50. data/lib/synvert/core/node_query/lexer.rex.rb +0 -299
  51. data/lib/synvert/core/node_query/parser.racc.rb +0 -306
  52. data/lib/synvert/core/node_query/parser.y +0 -60
  53. data/lib/synvert/core/node_query.rb +0 -36
  54. data/lib/synvert/core/rewriter/action/append_action.rb +0 -28
  55. data/lib/synvert/core/rewriter/action/delete_action.rb +0 -34
  56. data/lib/synvert/core/rewriter/action/insert_action.rb +0 -34
  57. data/lib/synvert/core/rewriter/action/insert_after_action.rb +0 -22
  58. data/lib/synvert/core/rewriter/action/prepend_action.rb +0 -44
  59. data/lib/synvert/core/rewriter/action/remove_action.rb +0 -56
  60. data/lib/synvert/core/rewriter/action/replace_action.rb +0 -33
  61. data/lib/synvert/core/rewriter/action/replace_with_action.rb +0 -36
  62. data/lib/synvert/core/rewriter/action/wrap_action.rb +0 -37
  63. data/lib/synvert/core/rewriter/action.rb +0 -102
  64. data/spec/synvert/core/node_query/lexer_spec.rb +0 -580
  65. data/spec/synvert/core/node_query/parser_spec.rb +0 -337
  66. data/spec/synvert/core/rewriter/action/append_action_spec.rb +0 -70
  67. data/spec/synvert/core/rewriter/action/delete_action_spec.rb +0 -26
  68. data/spec/synvert/core/rewriter/action/insert_action_spec.rb +0 -70
  69. data/spec/synvert/core/rewriter/action/insert_after_action_spec.rb +0 -26
  70. data/spec/synvert/core/rewriter/action/prepend_action_spec.rb +0 -175
  71. data/spec/synvert/core/rewriter/action/remove_action_spec.rb +0 -26
  72. data/spec/synvert/core/rewriter/action/replace_action_spec.rb +0 -28
  73. data/spec/synvert/core/rewriter/action/replace_with_action_spec.rb +0 -59
  74. data/spec/synvert/core/rewriter/action/wrap_action_spec.rb +0 -31
  75. data/spec/synvert/core/rewriter/action_spec.rb +0 -14
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # AppendAction appends code to the bottom of node body.
5
- class Rewriter::AppendAction < Rewriter::Action
6
- private
7
-
8
- END_LENGTH = "\nend".length
9
-
10
- # Calculate the begin the end positions.
11
- def calculate_position
12
- @begin_pos = :begin == @node.type ? @node.loc.expression.end_pos : @node.loc.expression.end_pos - @node.column - END_LENGTH
13
- @end_pos = @begin_pos
14
- end
15
-
16
- # Indent of the node.
17
- #
18
- # @param node [Parser::AST::Node]
19
- # @return [String] n times whitesphace
20
- def indent(node)
21
- if %i[block class def defs].include? node.type
22
- ' ' * (node.column + DEFAULT_INDENT)
23
- else
24
- ' ' * node.column
25
- end
26
- end
27
- end
28
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # DeleteAction deletes child nodes.
5
- class Rewriter::DeleteAction < Rewriter::Action
6
- # Initialize a DeleteAction.
7
- #
8
- # @param instance [Synvert::Core::Rewriter::Instance]
9
- # @param selectors [Array<Symbol, String>] used to select child nodes
10
- # @option and_comma [Boolean] delete extra comma.
11
- def initialize(instance, *selectors, and_comma: false)
12
- super(instance, nil)
13
- @selectors = selectors
14
- @and_comma = and_comma
15
- end
16
-
17
- # The rewritten code, always empty string.
18
- def rewritten_code
19
- ''
20
- end
21
-
22
- private
23
-
24
- # Calculate the begin and end positions.
25
- def calculate_position
26
- @begin_pos = @selectors.map { |selector| @node.child_node_range(selector) }
27
- .compact.map(&:begin_pos).min
28
- @end_pos = @selectors.map { |selector| @node.child_node_range(selector) }
29
- .compact.map(&:end_pos).max
30
- squeeze_spaces
31
- remove_comma if @and_comma
32
- end
33
- end
34
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # InsertAction to add code to the node.
5
- class Rewriter::InsertAction < Rewriter::Action
6
- # Initialize an InsertAction.
7
- #
8
- # @param instance [Synvert::Core::Rewriter::Instance]
9
- # @param code [String] to be inserted
10
- # @param at [String] position to insert, beginning or end
11
- # @param to [<Symbol|String>] name of child node
12
- def initialize(instance, code, at: 'end', to: nil)
13
- super(instance, code)
14
- @at = at
15
- @to = to
16
- end
17
-
18
- # The rewritten source code.
19
- #
20
- # @return [String] rewritten code.
21
- def rewritten_code
22
- rewritten_source
23
- end
24
-
25
- private
26
-
27
- # Calculate the begin and end positions.
28
- def calculate_position
29
- node_range = @to ? @node.child_node_range(@to) : @node.loc.expression
30
- @begin_pos = @at == 'end' ? node_range.end_pos : node_range.begin_pos
31
- @end_pos = @begin_pos
32
- end
33
- end
34
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # InsertAfterAction to insert code next to the node.
5
- class Rewriter::InsertAfterAction < Rewriter::Action
6
- private
7
-
8
- # Calculate the begin and end positions.
9
- def calculate_position
10
- @begin_pos = @node.loc.expression.end_pos
11
- @end_pos = @begin_pos
12
- end
13
-
14
- # Indent of the node.
15
- #
16
- # @param node [Parser::AST::Node]
17
- # @return [String] n times whitesphace
18
- def indent(node)
19
- ' ' * node.column
20
- end
21
- end
22
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # PrependAction to prepend code to the top of node body.
5
- class Rewriter::PrependAction < Rewriter::Action
6
- private
7
-
8
- DO_LENGTH = ' do'.length
9
-
10
- # Calculate the begin and end positions.
11
- def calculate_position
12
- @begin_pos =
13
- case @node.type
14
- when :block
15
- if @node.children[1].children.empty?
16
- @node.children[0].loc.expression.end_pos + DO_LENGTH
17
- else
18
- @node.children[1].loc.expression.end_pos
19
- end
20
- when :class
21
- @node.children[1] ? @node.children[1].loc.expression.end_pos : @node.children[0].loc.expression.end_pos
22
- when :def
23
- @node.children[1].empty? ? @node.loc.name.end_pos : @node.children[1].loc.expression.end_pos
24
- when :defs
25
- @node.children[2].empty? ? @node.loc.name.end_pos : @node.children[2].loc.expression.end_pos
26
- else
27
- @node.children.last.loc.expression.end_pos
28
- end
29
- @end_pos = @begin_pos
30
- end
31
-
32
- # Indent of the node.
33
- #
34
- # @param node [Parser::AST::Node]
35
- # @return [String] n times whitesphace
36
- def indent(node)
37
- if %i[block class def defs].include?(node.type)
38
- ' ' * (node.column + DEFAULT_INDENT)
39
- else
40
- ' ' * node.column
41
- end
42
- end
43
- end
44
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # RemoveAction to remove current node.
5
- class Rewriter::RemoveAction < Rewriter::Action
6
- # Initialize a RemoveAction.
7
- #
8
- # @param instance [Synvert::Core::Rewriter::RemoveAction]
9
- # @param options [Hash] options.
10
- # @option and_comma [Boolean] delete extra comma.
11
- def initialize(instance, and_comma: false)
12
- super(instance, nil)
13
- @and_comma = and_comma
14
- end
15
-
16
- # The rewritten code, always empty string.
17
- def rewritten_code
18
- ''
19
- end
20
-
21
- private
22
-
23
- # Calculate the begin the end positions.
24
- def calculate_position
25
- if take_whole_line?
26
- @begin_pos = start_index
27
- @end_pos = end_index
28
- squeeze_lines
29
- else
30
- @begin_pos = @node.loc.expression.begin_pos
31
- @end_pos = @node.loc.expression.end_pos
32
- squeeze_spaces
33
- remove_comma if @and_command
34
- end
35
- end
36
-
37
- # Check if the source code of current node takes the whole line.
38
- #
39
- # @return [Boolean]
40
- def take_whole_line?
41
- @node.to_source == file_source[start_index...end_index].strip
42
- end
43
-
44
- # Get the start position of the line
45
- def start_index
46
- index = file_source[0..@node.loc.expression.begin_pos].rindex("\n")
47
- index ? index + "\n".length : @node.loc.expression.begin_pos
48
- end
49
-
50
- # Get the end position of the line
51
- def end_index
52
- index = file_source[@node.loc.expression.end_pos..-1].index("\n")
53
- index ? @node.loc.expression.end_pos + index + "\n".length : @node.loc.expression.end_pos
54
- end
55
- end
56
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # ReplaceAction to replace child node with code.
5
- class Rewriter::ReplaceAction < Rewriter::Action
6
- # Initailize a ReplaceAction.
7
- #
8
- # @param instance [Synvert::Core::Rewriter::Instance]
9
- # @param selectors [Array<Symbol|String>] used to select child nodes
10
- # @param with [String] the new code
11
- def initialize(instance, *selectors, with:)
12
- super(instance, with)
13
- @selectors = selectors
14
- end
15
-
16
- # The rewritten source code.
17
- #
18
- # @return [String] rewritten code.
19
- def rewritten_code
20
- rewritten_source
21
- end
22
-
23
- private
24
-
25
- # Calculate the begin the end positions.
26
- def calculate_position
27
- @begin_pos = @selectors.map { |selector| @node.child_node_range(selector).begin_pos }
28
- .min
29
- @end_pos = @selectors.map { |selector| @node.child_node_range(selector).end_pos }
30
- .max
31
- end
32
- end
33
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # ReplaceWithAction to replace code.
5
- class Rewriter::ReplaceWithAction < Rewriter::Action
6
- # The rewritten source code with proper indent.
7
- #
8
- # @return [String] rewritten code.
9
- def rewritten_code
10
- if rewritten_source.include?("\n")
11
- new_code = []
12
- rewritten_source.split("\n").each_with_index do |line, index|
13
- new_code << (index == 0 ? line : indent + line)
14
- end
15
- new_code.join("\n")
16
- else
17
- rewritten_source
18
- end
19
- end
20
-
21
- private
22
-
23
- # Calculate the begin the end positions.
24
- def calculate_position
25
- @begin_pos = @node.loc.expression.begin_pos
26
- @end_pos = @node.loc.expression.end_pos
27
- end
28
-
29
- # Indent of the node
30
- #
31
- # @return [String] n times whitesphace
32
- def indent
33
- ' ' * @node.column
34
- end
35
- end
36
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # WrapAction to warp node within a block, class or module.
5
- #
6
- # Note: if WrapAction is conflicted with another action (begin_pos and end_pos are overlapped),
7
- # we have to put those 2 actions into 2 within_file scopes.
8
- class Rewriter::WrapAction < Rewriter::Action
9
- # Initialize a WrapAction.
10
- #
11
- # @param instance [Synvert::Core::Rewriter::WrapAction]
12
- # @param with [String] new code to wrap
13
- # @param indent [Integer, nil] number of whitespaces
14
- def initialize(instance, with:, indent: nil)
15
- super(instance, with)
16
- @indent = indent || @node.column
17
- end
18
-
19
- # The rewritten source code.
20
- #
21
- # @return [String] rewritten code.
22
- def rewritten_code
23
- "#{@code}\n#{' ' * @indent}" +
24
- @node.to_source.split("\n").map { |line| " #{line}" }
25
- .join("\n") +
26
- "\n#{' ' * @indent}end"
27
- end
28
-
29
- private
30
-
31
- # Calculate the begin the end positions.
32
- def calculate_position
33
- @begin_pos = @node.loc.expression.begin_pos
34
- @end_pos = @node.loc.expression.end_pos
35
- end
36
- end
37
- end
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # Action defines rewriter action, insert, replace or delete code.
5
- class Rewriter::Action
6
- DEFAULT_INDENT = 2
7
-
8
- # @!attribute [r] begin_pos
9
- # @return [Integer] begin position
10
- # @!attribute [r] end_pos
11
- # @return [Integer] end position
12
- attr_reader :begin_pos, :end_pos
13
-
14
- # Initialize an action.
15
- #
16
- # @param instance [Synvert::Core::Rewriter::Instance]
17
- # @param code [String] new code to insert, replace or delete.
18
- def initialize(instance, code)
19
- @instance = instance
20
- @code = code
21
- @node = @instance.current_node
22
- end
23
-
24
- # Calculate begin and end positions, and return self.
25
- #
26
- # @return [Synvert::Core::Rewriter::Action] self
27
- def process
28
- calculate_position
29
- self
30
- end
31
-
32
- # The rewritten source code with proper indent.
33
- #
34
- # @return [String] rewritten code.
35
- def rewritten_code
36
- if rewritten_source.split("\n").length > 1
37
- "\n\n" + rewritten_source.split("\n").map { |line| indent(@node) + line }
38
- .join("\n")
39
- else
40
- "\n" + indent(@node) + rewritten_source
41
- end
42
- end
43
-
44
- protected
45
-
46
- # Calculate the begin the end positions.
47
- #
48
- # @abstract
49
- def calculate_position
50
- raise NotImplementedError, 'must be implemented by subclasses'
51
- end
52
-
53
- # The rewritten source code.
54
- #
55
- # @return [String] rewritten source code.
56
- def rewritten_source
57
- @rewritten_source ||= @node.rewritten_source(@code)
58
- end
59
-
60
- # Squeeze spaces from source code.
61
- def squeeze_spaces
62
- if file_source[@begin_pos - 1] == ' ' && file_source[@end_pos] == ' '
63
- @begin_pos -= 1
64
- end
65
- end
66
-
67
- # Squeeze empty lines from source code.
68
- def squeeze_lines
69
- lines = file_source.split("\n")
70
- begin_line = @node.loc.expression.first_line
71
- end_line = @node.loc.expression.last_line
72
- before_line_is_blank = begin_line == 1 || lines[begin_line - 2] == ''
73
- after_line_is_blank = lines[end_line] == ''
74
-
75
- if lines.length > 1 && before_line_is_blank && after_line_is_blank
76
- @end_pos += "\n".length
77
- end
78
- end
79
-
80
- # Remove unused comma.
81
- # e.g. `foobar(foo, bar)`, if we remove `foo`, the comma should also be removed,
82
- # the code should be changed to `foobar(bar)`.
83
- def remove_comma
84
- if ',' == file_source[@begin_pos - 1]
85
- @begin_pos -= 1
86
- elsif ', ' == file_source[@begin_pos - 2, 2]
87
- @begin_pos -= 2
88
- elsif ', ' == file_source[@end_pos, 2]
89
- @end_pos += 2
90
- elsif ',' == file_source[@end_pos]
91
- @end_pos += 1
92
- end
93
- end
94
-
95
- # Return file source.
96
- #
97
- # @return [String]
98
- def file_source
99
- @file_source ||= @instance.file_source
100
- end
101
- end
102
- end