Module: CArray::FuseSource
- Defined in:
- lib/carray/fuse_source.rb
Defined Under Namespace
Classes: Leaves
Class Method Summary collapse
-
.body_source(block) ⇒ Object
-- the block's own text ---------------------------------------------.
- .evaluate(block) ⇒ Object
- .extract(block) ⇒ Object
- .rewrite(source) ⇒ Object
-
.shadow(value) ⇒ Object
Runtime coercion, so the rewrite never has to work out what a name holds: anything that is not an array passes through untouched.
Class Method Details
.body_source(block) ⇒ Object
-- the block's own text ---------------------------------------------
38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/carray/fuse_source.rb', line 38 def self.body_source (block) text = extract(block) wrapped = "proc " + text node = Prism.parse(wrapped).value .breadth_first_search { |n| n.is_a?(Prism::BlockNode) } inner = node && node.body unless inner raise ArgumentError, "CArray.fuse could not read an expression out of this block" end wrapped.byteslice(inner.location.start_offset...inner.location.end_offset) end |
.evaluate(block) ⇒ Object
28 29 30 31 32 33 34 |
# File 'lib/carray/fuse_source.rb', line 28 def self.evaluate (block) result = eval(rewrite(body_source(block)), block.binding, *block.source_location) # An expression that is just an array is that array; the shadow put # around it has nothing to fuse. result.is_a?(CALazyMarker) ? result.parent : result end |
.extract(block) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/carray/fuse_source.rb', line 51 def self.extract (block) sequence = RubyVM::InstructionSequence.of(block) rescue nil location = sequence && sequence.to_a[4][:code_location] path = sequence && (sequence.absolute_path || sequence.path) unless location && path && File.readable?(path) raise ArgumentError, "CArray.fuse cannot read this block's source (defined in irb, " \ "eval, or a file that is no longer there). Write `.lazy` on " \ "the operands instead: `a.lazy + b.lazy`." end lines = File.readlines(path) first_line, first_column, last_line, last_column = location # The columns count bytes, not characters, so a line with anything # multi-byte on it slices in the wrong place unless this does too. if first_line == last_line lines[first_line - 1].byteslice(first_column...last_column) else [lines[first_line - 1].byteslice(first_column..), *lines[first_line...(last_line - 1)], lines[last_line - 1].byteslice(0...last_column)].join end end |
.rewrite(source) ⇒ Object
113 114 115 116 117 118 119 120 121 |
# File 'lib/carray/fuse_source.rb', line 113 def self.rewrite (source) visitor = Leaves.new Prism.parse(source).value.accept(visitor) out = source.dup visitor.spots.sort_by { |start, _| -start }.each do |start, stop| out[start...stop] = "::CArray::FuseSource.shadow(#{source[start...stop]})" end out end |
.shadow(value) ⇒ Object
Runtime coercion, so the rewrite never has to work out what a name holds: anything that is not an array passes through untouched.
24 25 26 |
# File 'lib/carray/fuse_source.rb', line 24 def self.shadow (value) value.is_a?(CArray) ? value.lazy : value end |