ripper2ruby 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.
Files changed (111) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.markdown +10 -0
  3. data/lib/core_ext/array/flush.rb +5 -0
  4. data/lib/core_ext/hash/delete_at.rb +5 -0
  5. data/lib/core_ext/object/meta_class.rb +5 -0
  6. data/lib/core_ext/object/try.rb +12 -0
  7. data/lib/erb/stripper.rb +48 -0
  8. data/lib/highlighters/ansi.rb +29 -0
  9. data/lib/ripper/event_log.rb +45 -0
  10. data/lib/ripper/ruby_builder.rb +168 -0
  11. data/lib/ripper/ruby_builder/buffer.rb +34 -0
  12. data/lib/ripper/ruby_builder/events/args.rb +40 -0
  13. data/lib/ripper/ruby_builder/events/array.rb +71 -0
  14. data/lib/ripper/ruby_builder/events/assignment.rb +55 -0
  15. data/lib/ripper/ruby_builder/events/block.rb +80 -0
  16. data/lib/ripper/ruby_builder/events/call.rb +123 -0
  17. data/lib/ripper/ruby_builder/events/case.rb +17 -0
  18. data/lib/ripper/ruby_builder/events/const.rb +47 -0
  19. data/lib/ripper/ruby_builder/events/for.rb +13 -0
  20. data/lib/ripper/ruby_builder/events/hash.rb +24 -0
  21. data/lib/ripper/ruby_builder/events/identifier.rb +41 -0
  22. data/lib/ripper/ruby_builder/events/if.rb +37 -0
  23. data/lib/ripper/ruby_builder/events/lexer.rb +159 -0
  24. data/lib/ripper/ruby_builder/events/literal.rb +47 -0
  25. data/lib/ripper/ruby_builder/events/method.rb +21 -0
  26. data/lib/ripper/ruby_builder/events/operator.rb +23 -0
  27. data/lib/ripper/ruby_builder/events/statements.rb +50 -0
  28. data/lib/ripper/ruby_builder/events/string.rb +117 -0
  29. data/lib/ripper/ruby_builder/events/symbol.rb +22 -0
  30. data/lib/ripper/ruby_builder/events/while.rb +27 -0
  31. data/lib/ripper/ruby_builder/queue.rb +33 -0
  32. data/lib/ripper/ruby_builder/stack.rb +125 -0
  33. data/lib/ripper/ruby_builder/token.rb +91 -0
  34. data/lib/ripper2ruby.rb +1 -0
  35. data/lib/ruby.rb +28 -0
  36. data/lib/ruby/aggregate.rb +71 -0
  37. data/lib/ruby/alternation/args.rb +25 -0
  38. data/lib/ruby/alternation/hash.rb +25 -0
  39. data/lib/ruby/alternation/list.rb +19 -0
  40. data/lib/ruby/args.rb +36 -0
  41. data/lib/ruby/array.rb +27 -0
  42. data/lib/ruby/assignment.rb +32 -0
  43. data/lib/ruby/assoc.rb +17 -0
  44. data/lib/ruby/block.rb +42 -0
  45. data/lib/ruby/call.rb +34 -0
  46. data/lib/ruby/case.rb +30 -0
  47. data/lib/ruby/const.rb +49 -0
  48. data/lib/ruby/for.rb +18 -0
  49. data/lib/ruby/hash.rb +14 -0
  50. data/lib/ruby/if.rb +35 -0
  51. data/lib/ruby/list.rb +40 -0
  52. data/lib/ruby/literal.rb +45 -0
  53. data/lib/ruby/method.rb +19 -0
  54. data/lib/ruby/node.rb +47 -0
  55. data/lib/ruby/node/composite.rb +68 -0
  56. data/lib/ruby/node/conversions.rb +66 -0
  57. data/lib/ruby/node/position.rb +35 -0
  58. data/lib/ruby/node/source.rb +29 -0
  59. data/lib/ruby/node/text.rb +121 -0
  60. data/lib/ruby/node/traversal.rb +82 -0
  61. data/lib/ruby/operator.rb +49 -0
  62. data/lib/ruby/params.rb +41 -0
  63. data/lib/ruby/statements.rb +45 -0
  64. data/lib/ruby/string.rb +40 -0
  65. data/lib/ruby/symbol.rb +27 -0
  66. data/lib/ruby/token.rb +51 -0
  67. data/lib/ruby/while.rb +32 -0
  68. data/test/all.rb +3 -0
  69. data/test/builder/stack_test.rb +67 -0
  70. data/test/builder/text_test.rb +118 -0
  71. data/test/context_test.rb +54 -0
  72. data/test/erb_stripper_test.rb +29 -0
  73. data/test/fixtures/all.rb.src +150 -0
  74. data/test/fixtures/source_1.rb +16 -0
  75. data/test/fixtures/source_2.rb +1 -0
  76. data/test/fixtures/stuff.rb +371 -0
  77. data/test/fixtures/template.html.erb +22 -0
  78. data/test/fixtures/tmp.rb +6 -0
  79. data/test/lib_test.rb +92 -0
  80. data/test/lib_test_helper.rb +103 -0
  81. data/test/libs.txt +227 -0
  82. data/test/nodes/args_test.rb +100 -0
  83. data/test/nodes/array_test.rb +141 -0
  84. data/test/nodes/assignment_test.rb +49 -0
  85. data/test/nodes/block_test.rb +125 -0
  86. data/test/nodes/call_test.rb +229 -0
  87. data/test/nodes/case_test.rb +68 -0
  88. data/test/nodes/comments_test.rb +25 -0
  89. data/test/nodes/const_test.rb +46 -0
  90. data/test/nodes/conversions_test.rb +9 -0
  91. data/test/nodes/for_test.rb +34 -0
  92. data/test/nodes/hash_test.rb +71 -0
  93. data/test/nodes/heredoc_test.rb +202 -0
  94. data/test/nodes/identifier_test.rb +51 -0
  95. data/test/nodes/if_test.rb +100 -0
  96. data/test/nodes/literals_test.rb +63 -0
  97. data/test/nodes/method_test.rb +92 -0
  98. data/test/nodes/namespaces_test.rb +65 -0
  99. data/test/nodes/node_test.rb +74 -0
  100. data/test/nodes/nodes_test.rb +23 -0
  101. data/test/nodes/operator_test.rb +241 -0
  102. data/test/nodes/separators_test.rb +97 -0
  103. data/test/nodes/statements_test.rb +70 -0
  104. data/test/nodes/string_test.rb +92 -0
  105. data/test/nodes/symbol_test.rb +57 -0
  106. data/test/nodes/unless_test.rb +42 -0
  107. data/test/nodes/until_test.rb +61 -0
  108. data/test/nodes/while_test.rb +71 -0
  109. data/test/test_helper.rb +51 -0
  110. data/test/traversal_test.rb +53 -0
  111. metadata +163 -0
data/lib/ruby/node.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'core_ext/object/meta_class'
2
+ require 'core_ext/object/try'
3
+ require 'ruby/node/composite'
4
+ require 'ruby/node/source'
5
+ require 'ruby/node/traversal'
6
+ require 'ruby/node/conversions'
7
+
8
+ module Ruby
9
+ class Node
10
+ include Comparable
11
+ include Composite
12
+ include Source
13
+ include Traversal
14
+ include Conversions
15
+
16
+ def row
17
+ position[0]
18
+ end
19
+
20
+ def column
21
+ position[1]
22
+ end
23
+
24
+ def length(prolog = false)
25
+ to_ruby(prolog).length
26
+ end
27
+
28
+ def nodes
29
+ []
30
+ end
31
+
32
+ def all_nodes
33
+ nodes + nodes.map { |node| node.all_nodes }.flatten
34
+ end
35
+
36
+ def <=>(other)
37
+ position <=> (other.respond_to?(:position) ? other.position : other)
38
+ end
39
+
40
+ protected
41
+ def update_positions(row, column, offset_column)
42
+ pos = self.position
43
+ pos.col += offset_column if pos && self.row == row && self.column > column
44
+ nodes.each { |c| c.send(:update_positions, row, column, offset_column) }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,68 @@
1
+ module Ruby
2
+ class Node
3
+ module Composite
4
+ class Array < ::Array
5
+ include Composite
6
+
7
+ def initialize(objects = [])
8
+ objects.each { |object| self << object }
9
+ end
10
+
11
+ def detect
12
+ each { |element| return element if yield(element) }
13
+ end
14
+
15
+ def <<(object)
16
+ if object.respond_to?(:parent=)
17
+ object.parent = self.parent
18
+ elsif object.respond_to?(:each)
19
+ object.each { |o| o.try(:parent=, parent) }
20
+ end
21
+ super
22
+ end
23
+
24
+ def []=(ix, object)
25
+ object.parent = parent
26
+ super
27
+ end
28
+
29
+ def parent=(parent)
30
+ each { |object| object.try(:parent=, parent) }
31
+ @parent = parent
32
+ end
33
+
34
+ def +(other)
35
+ self.dup.tap { |dup| other.each { |object| dup << object } }
36
+ end
37
+ end
38
+
39
+ def self.included(target)
40
+ target.class_eval do
41
+ class << self
42
+ def child_accessor(*names, &block)
43
+ names.each do |name|
44
+ attr_reader name
45
+ define_method("#{name}=") do |value|
46
+ value = Composite::Array.new(value) if value.is_a?(::Array)
47
+ value.parent = self if value
48
+ instance_variable_set(:"@#{name}", value)
49
+ yield(value) if block_given?
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ attr_accessor :parent
58
+
59
+ def root?
60
+ parent.nil?
61
+ end
62
+
63
+ def root
64
+ root? ? self : parent.root
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,66 @@
1
+ module Ruby
2
+ module Conversions
3
+ class << self
4
+ def included(target)
5
+ target.send(:extend, ClassMethods)
6
+ end
7
+ end
8
+
9
+ def to_node(node, position, prolog)
10
+ node = self.class.from_native(node) unless node.is_a?(Node)
11
+ node.position = position
12
+ node.prolog = prolog
13
+ node
14
+ end
15
+
16
+ module ClassMethods
17
+ def from_native(object, position = nil, prolog = nil)
18
+ from_ruby(object.inspect, position, prolog)
19
+ end
20
+
21
+ def from_ruby(src, position = nil, prolog = nil)
22
+ Ripper::RubyBuilder.new(src).parse.statements.first.tap do |node|
23
+ node.position = position if position
24
+ node.prolog = prolog if prolog
25
+ end
26
+ end
27
+ end
28
+
29
+ module Token
30
+ def to_identifier
31
+ Identifier.new(token, position, prolog)
32
+ end
33
+
34
+ def to_string_content
35
+ Ruby::StringContent.new(token, position, prolog)
36
+ end
37
+ end
38
+
39
+ module List
40
+ def to_array(ldelim, rdelim)
41
+ Ruby::Array.new(elements, ldelim, rdelim)
42
+ end
43
+ end
44
+
45
+ module Statements
46
+ def to_block(params = nil, ldelim = nil, rdelim = nil)
47
+ Block.new(elements, params, ldelim, rdelim)
48
+ end
49
+
50
+ def to_named_block(identifier = nil, params = nil, ldelim = nil, rdelim = nil)
51
+ NamedBlock.new(identifier = nil, elements, params, ldelim, rdelim)
52
+ end
53
+
54
+ def to_chained_block(identifier = nil, blocks = nil, params = nil, ldelim = nil, rdelim = nil)
55
+ ldelim ||= self.ldelim
56
+ rdelim ||= self.rdelim
57
+ identifier ||= self.identifier if respond_to?(:identifier)
58
+ ChainedBlock.new(identifier, blocks, elements, params, ldelim, rdelim)
59
+ end
60
+
61
+ def to_program(src, filename, end_data)
62
+ Program.new(src, filename, elements, end_data)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,35 @@
1
+ module Ruby
2
+ class Node
3
+ class Position
4
+ include Comparable
5
+
6
+ attr_accessor :row, :col
7
+
8
+ def initialize(row, col)
9
+ @row = row
10
+ @col = col
11
+ end
12
+
13
+ def [](ix)
14
+ ix == 0 ? row : col
15
+ end
16
+
17
+ def <=>(other)
18
+ row < other.row ? -1 : row > other.row ? 1 : col <=> other.col
19
+ end
20
+
21
+ def ==(other)
22
+ to_a == other.to_a
23
+ end
24
+ alias eql? ==
25
+
26
+ def to_a
27
+ [row, col]
28
+ end
29
+
30
+ def inspect
31
+ to_a.inspect
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ require 'ruby/node/text'
2
+
3
+ module Ruby
4
+ class Node
5
+ module Source
6
+ def filename
7
+ root? ? @filename : root.filename
8
+ end
9
+
10
+ def src(prolog = false)
11
+ root? ? @src : Ruby::Node::Text.new(root.src).clip(position(prolog), length(prolog)).to_s
12
+ end
13
+
14
+ def lines
15
+ root.src.split("\n")
16
+ end
17
+
18
+ def line
19
+ Ruby::Node::Text.new(lines[row]).clip([0, column], length)
20
+ end
21
+
22
+ def context(options = {})
23
+ filter = options.has_key?(:highlight) ? options[:highlight] : false
24
+ line = filter ? self.line.head + filter.highlight(to_ruby) + self.line.tail : nil
25
+ Ruby::Node::Text::Context.new(lines, row, options[:width] || 2, line).to_s
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,121 @@
1
+ require 'ruby/node/position'
2
+
3
+ module Ruby
4
+ class Node
5
+ class Text
6
+ class << self
7
+ def split(str)
8
+ str.gsub(/\n/, "\n\000").split(/\000/)
9
+ end
10
+ end
11
+
12
+ class Context
13
+ @@context_width = 2
14
+
15
+ class << self
16
+ def context_width
17
+ @@context_width
18
+ end
19
+
20
+ def context_width=(context_width)
21
+ @@context_width = context_width
22
+ end
23
+ end
24
+
25
+ attr_reader :lines, :line, :row, :width
26
+
27
+ def initialize(lines, row, width = nil, line = nil)
28
+ @lines = lines
29
+ @line = line || lines[row]
30
+ @row = row
31
+ @width = width || Context.width
32
+ end
33
+
34
+ def to_s(options = {})
35
+ (head + [line] + tail).join("\n")
36
+ end
37
+
38
+ protected
39
+
40
+ def head
41
+ min = [0, row - width].max
42
+ min < row ? lines[min..(row - 1)] : []
43
+ end
44
+
45
+ def tail
46
+ max = [row + width, lines.size].min
47
+ max > row ? lines[(row + 1)..max] : []
48
+ end
49
+ end
50
+
51
+ class Clip
52
+ attr_reader :lines, :row, :col, :length, :end
53
+
54
+ def initialize(lines, pos, length = nil)
55
+ @lines = lines.is_a?(::String) ? Text.split(lines) : lines
56
+ @row, @col = *pos
57
+ @length = length.nil? ? self.lines.join.length : length
58
+ init
59
+ end
60
+
61
+ def end
62
+ @end ||= Position.new(row, col + self.length)
63
+ end
64
+
65
+ def end=(position)
66
+ @end = Position.new(*position)
67
+ end
68
+
69
+ def head
70
+ lines[0, row].join + lines[row][0, col]
71
+ end
72
+
73
+ def tail
74
+ lines[self.end.row][self.end.col..-1] + lines[(self.end.row + 1)..-1].join
75
+ end
76
+
77
+ def src
78
+ lines.join
79
+ end
80
+
81
+ def to_s
82
+ @string
83
+ end
84
+
85
+ protected
86
+
87
+ def init # TODO how to simplify this?
88
+ @string = lines[row][col, self.length]
89
+ col = self.length - @string.length
90
+ row = self.row + 1
91
+ while (line = lines[row]) && col > 0
92
+ @string << line[0..(col - 1)]
93
+ if col - line.length >= 0
94
+ col -= line.length
95
+ row += 1
96
+ self.end = [row, col]
97
+ else
98
+ self.end = [row, col]
99
+ break
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ attr_reader :str, :sep
106
+
107
+ def initialize(str = '', sep = nil)
108
+ @str = str
109
+ @sep = sep || "\n"
110
+ end
111
+
112
+ def lines
113
+ @lines ||= Text.split(str)
114
+ end
115
+
116
+ def clip(pos, length)
117
+ Clip.new(lines, pos, length)
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,82 @@
1
+ module Ruby
2
+ class Node
3
+ module Traversal
4
+ def select(*args, &block)
5
+ result = []
6
+ result << self if matches?(args.dup, &block)
7
+
8
+ children = (prolog.try(:elements).to_a || []) + nodes
9
+ children.flatten.compact.inject(result) do |result, node|
10
+ result + node.select(*args, &block)
11
+ end
12
+ end
13
+
14
+ def matches?(args, &block)
15
+ conditions = args.last.is_a?(::Hash) ? args.pop : {}
16
+ conditions[:is_a] = args unless args.empty?
17
+
18
+ conditions.inject(!conditions.empty?) do |result, (type, value)|
19
+ result && case type
20
+ when :is_a
21
+ has_type?(value)
22
+ when :class
23
+ is_instance_of?(value)
24
+ when :token
25
+ has_token?(value)
26
+ when :value
27
+ has_value?(value)
28
+ when :pos, :position
29
+ position?(value)
30
+ when :right_of
31
+ right_of?(value)
32
+ when :left_of
33
+ left_of?(value)
34
+ end
35
+ end && (!block_given? || block.call(self))
36
+ end
37
+
38
+ def has_type?(klass)
39
+ case klass
40
+ when ::Array
41
+ klass.each { |klass| return true if has_type?(klass) } and false
42
+ else
43
+ is_a?(klass) # allow to pass a symbol or string, too
44
+ end
45
+ end
46
+
47
+ def is_instance_of?(klass)
48
+ case klass
49
+ when ::Array
50
+ klass.each { |klass| return true if has_type?(klass) } and false
51
+ else
52
+ instance_of?(klass) # allow to pass a symbol or string, too
53
+ end
54
+ end
55
+
56
+ def has_token?(token)
57
+ case token
58
+ when ::Array
59
+ type.each { |type| return true if has_token?(token) } and false
60
+ else
61
+ self.token == token
62
+ end if respond_to?(:token)
63
+ end
64
+
65
+ def has_value?(value)
66
+ self.value == value if respond_to?(:value)
67
+ end
68
+
69
+ def position?(pos)
70
+ position == pos
71
+ end
72
+
73
+ def left_of?(right)
74
+ right.nil? || self.position < right.position
75
+ end
76
+
77
+ def right_of?(left)
78
+ left.nil? || left.position < self.position
79
+ end
80
+ end
81
+ end
82
+ end