Class: Maccro::Rule

Inherits:
Object
  • Object
show all
Defined in:
lib/maccro/rule.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, before, after, under: nil, safe_reference: false) ⇒ Rule

Returns a new instance of Rule.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/maccro/rule.rb', line 9

def initialize(name, before, after, under: nil, safe_reference: false)
  @name = name
  @before = before
  @after = after
  @under = under
  @safe_reference = safe_reference

  # TODO: check all placeholder in @after exist in @before
  # (placeholders in @before are not required to exist in @after, because it may be removed)
  # TODO: check $TARGET exists in under just once

  # TODO: implement a matcher in @before matches in multi times

  @matcher = DSL.matcher(before)
  @pruner = under && DSL.matcher(under) || nil
end

Instance Attribute Details

#afterObject (readonly)

Returns the value of attribute after.



7
8
9
# File 'lib/maccro/rule.rb', line 7

def after
  @after
end

#beforeObject (readonly)

Returns the value of attribute before.



7
8
9
# File 'lib/maccro/rule.rb', line 7

def before
  @before
end

#matcherObject (readonly)

Returns the value of attribute matcher.



7
8
9
# File 'lib/maccro/rule.rb', line 7

def matcher
  @matcher
end

#nameObject (readonly)

Returns the value of attribute name.



7
8
9
# File 'lib/maccro/rule.rb', line 7

def name
  @name
end

#safe_referenceObject (readonly)

Returns the value of attribute safe_reference.



7
8
9
# File 'lib/maccro/rule.rb', line 7

def safe_reference
  @safe_reference
end

#underObject (readonly)

Returns the value of attribute under.



7
8
9
# File 'lib/maccro/rule.rb', line 7

def under
  @under
end

Class Method Details

.find_placeholder_code_ranges(ast, name) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/maccro/rule.rb', line 72

def self.find_placeholder_code_ranges(ast, name)
  return [] unless ast.is_a? RubyVM::AbstractSyntaxTree::Node

  if ast.type == :VCALL && ast.children.first.to_s == name
    return [CodeRange.from_node(ast)]
  end

  ranges = []
  ast.children.each do |c|
    rs = find_placeholder_code_ranges(c, name)
    ranges.concat(rs) unless rs.empty?
  end
  ranges.sort
end

Instance Method Details

#after_code(replace_pairs) ⇒ Object

name => snippet



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/maccro/rule.rb', line 87

def after_code(replace_pairs) # name => snippet
  code = @after.dup
  ast = CodeUtil.parse_to_ast(@after)
  code_range_to_name = {}
  replace_pairs.each_key do |name|
    self.class.find_placeholder_code_ranges(ast, name).each do |r|
      code_range_to_name[r] = name
    end
  end
  # reverse is not to break code position for unprocessed code ranges
  code_range_to_name.keys.sort.reverse.each do |code_range|
    name = code_range_to_name[code_range]
    snippet = replace_pairs[name]
    range = CodeUtil.code_range_to_range(@after.dup, code_range)
    code[range] = snippet
  end
  code
end

#dig_match(matches, ast) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/maccro/rule.rb', line 56

def dig_match(matches, ast)
  if @matcher.match?(ast)
    placeholders = {}
    @matcher.capture(ast, placeholders)
    matches << Match.new(rule: self, placeholders: placeholders, range: ast.to_code_range)
  elsif ast.respond_to?(:children)
    ast.children.each do |c|
      dig_match(matches, c)
    end
  elsif ast.respond_to?(:each)
    ast.each do |i|
      dig_match(matches, i)
    end
  end
end

#dig_prune(matches, ast) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/maccro/rule.rb', line 40

def dig_prune(matches, ast)
  if @pruner.match?(ast)
    placeholders = {}
    @pruner.capture(ast, placeholders)
    dig_match(matches, placeholders[:__target__])
  elsif ast.respond_to?(:children)
    ast.children.each do |c|
      dig_prune(matches, c)
    end
  elsif ast.respond_to?(:each)
    ast.each do |i|
      dig_prune(matches, i)
    end
  end
end

#match(ast) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/maccro/rule.rb', line 26

def match(ast)
  matches = []

  if @pruner
    dig_prune(matches, ast)
  else
    dig_match(matches, ast)
  end

  return nil if matches.empty?

  Matched.new(matches)
end