Class: RipperTags::Parser

Inherits:
Ripper
  • Object
show all
Defined in:
lib/ripper-tags/parser.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extract(data, file = '(eval)') ⇒ Object



6
7
8
9
# File 'lib/ripper-tags/parser.rb', line 6

def self.extract(data, file='(eval)')
  sexp = new(data, file).parse
  Visitor.new(sexp, file, data).tags
end

Instance Method Details

#on_alias(lhs, rhs) ⇒ Object



37
38
39
# File 'lib/ripper-tags/parser.rb', line 37

def on_alias(lhs, rhs)
  [:alias, lhs[0], rhs[0], rhs[1]] if lhs && rhs
end

#on_aref_field(*args) ⇒ Object



53
54
55
# File 'lib/ripper-tags/parser.rb', line 53

def on_aref_field(*args)
  [:aref_field, *args]
end

#on_args_add(sub, arg) ⇒ Object



192
193
194
195
196
197
198
# File 'lib/ripper-tags/parser.rb', line 192

def on_args_add(sub, arg)
  if sub
    sub + [arg]
  else
    [:args, arg].compact
  end
end

#on_assign(lhs, rhs) ⇒ Object



40
41
42
43
44
45
46
# File 'lib/ripper-tags/parser.rb', line 40

def on_assign(lhs, rhs)
  return if lhs.nil?
  return if lhs[0] == :field
  return if lhs[0] == :aref_field
  lhs, line = lhs
  [:assign, lhs, rhs, line]
end

#on_binary(*args) ⇒ Object



64
65
# File 'lib/ripper-tags/parser.rb', line 64

def on_binary(*args)
end

#on_bodystmt(*args) ⇒ Object



77
78
79
# File 'lib/ripper-tags/parser.rb', line 77

def on_bodystmt(*args)
  args
end

#on_call(lhs, op, rhs) ⇒ Object



114
115
116
117
118
# File 'lib/ripper-tags/parser.rb', line 114

def on_call(lhs, op, rhs)
  return unless lhs && rhs
  arg = block = nil
  [:call, lhs[0], rhs[0], arg, block]
end

#on_class(name, superclass, body) ⇒ Object



26
27
28
29
# File 'lib/ripper-tags/parser.rb', line 26

def on_class(name, superclass, body)
  superclass.flatten!(1) if superclass
  [:class, name, superclass, *body.compact]
end

#on_command(name, *args) ⇒ Object



67
68
69
70
71
72
73
74
75
76
# File 'lib/ripper-tags/parser.rb', line 67

def on_command(name, *args)
  case name[0]
  when "define_method", "alias_method",
       "has_one", "has_many",
       "belongs_to", "has_and_belongs_to_many",
       "scope", "named_scope",
       /^attr_(accessor|reader|writer)$/
    on_method_add_arg([:fcall, name], args[0])
  end
end

#on_command_call(*args) ⇒ Object

handle ‘Class.new arg` call without parens



178
179
180
181
182
183
184
185
186
# File 'lib/ripper-tags/parser.rb', line 178

def on_command_call(*args)
  if args.last && :args == args.last[0]
    args_add = args.pop
    call = on_call(*args)
    on_method_add_arg(call, args_add)
  else
    super
  end
end

#on_const_path_ref(a, b) ⇒ Object Also known as: on_const_path_field



57
58
59
60
61
# File 'lib/ripper-tags/parser.rb', line 57

def on_const_path_ref(a, b)
  return if a.nil? || b.nil?
  a.flatten!(1)
  [[a && a[0], b[0]].join('::'), b[1]]
end

#on_def(method, args, body) ⇒ Object



30
31
32
# File 'lib/ripper-tags/parser.rb', line 30

def on_def(method, args, body)
  [:def, *method]
end

#on_defs(receiver, op, method, args, body) ⇒ Object



33
34
35
36
# File 'lib/ripper-tags/parser.rb', line 33

def on_defs(receiver, op, method, args, body)
  receiver.flatten!(1) if receiver
  [:defs, receiver && receiver[0], *method]
end

#on_do_block(*args) ⇒ Object



200
201
202
# File 'lib/ripper-tags/parser.rb', line 200

def on_do_block(*args)
  args
end

#on_dyna_symbol(*args) ⇒ Object



91
92
93
94
95
# File 'lib/ripper-tags/parser.rb', line 91

def on_dyna_symbol(*args)
  if args.length == 1 && args[0]
    [args[0], lineno]
  end
end

#on_fcall(*args) ⇒ Object



188
189
190
# File 'lib/ripper-tags/parser.rb', line 188

def on_fcall(*args)
  [:fcall, *args]
end

#on_field(lhs, op, rhs) ⇒ Object



50
51
52
# File 'lib/ripper-tags/parser.rb', line 50

def on_field(lhs, op, rhs)
  [:field, lhs && lhs[0], rhs[0], rhs[1]]
end

#on_if(condition, success, failure) ⇒ Object Also known as: on_unless



80
81
82
83
# File 'lib/ripper-tags/parser.rb', line 80

def on_if(condition, success, failure)
  ret = [success, failure].flatten(1).compact
  ret.any?? ret : nil
end

#on_method_add_arg(call, args) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/ripper-tags/parser.rb', line 120

def on_method_add_arg(call, args)
  call_name = call && call[0]
  first_arg = args && :args == args[0] && args[1]

  if :call == call_name && first_arg
    if args.length == 2
      # augment call if a single argument was used
      call = call.dup
      call[3] = args[1]
    end
    call
  elsif :fcall == call_name && first_arg
    name, line = call[1]
    case name
    when "alias_method"
      [:alias, args[1][0], args[2][0], line] if args[1] && args[2]
    when "define_method"
      [:def, args[1][0], line]
    when "scope", "named_scope"
      [:rails_def, :scope, args[1][0], line]
    when /^attr_(accessor|reader|writer)$/
      gen_reader = $1 != 'writer'
      gen_writer = $1 != 'reader'
      args[1..-1].inject([]) do |gen, arg|
        gen << [:def, arg[0], line] if gen_reader
        gen << [:def, "#{arg[0]}=", line] if gen_writer
        gen
      end
    when "has_many", "has_and_belongs_to_many"
      a = args[1][0]
      kind = name.to_sym
      gen = []
      unless a.is_a?(Enumerable) && !a.is_a?(String)
        a = a.to_s
        gen << [:rails_def, kind, a, line]
        gen << [:rails_def, kind, "#{a}=", line]
        if (sing = a.chomp('s')) != a
          # poor man's singularize
          gen << [:rails_def, kind, "#{sing}_ids", line]
          gen << [:rails_def, kind, "#{sing}_ids=", line]
        end
      end
      gen
    when "belongs_to", "has_one"
      a = args[1][0]
      unless a.is_a?(Enumerable) && !a.is_a?(String)
        kind = name.to_sym
        %W[ #{a} #{a}= build_#{a} create_#{a} create_#{a}! ].inject([]) do |all, ident|
          all << [:rails_def, kind, ident, line]
        end
      end
    end
  else
    super
  end
end

#on_method_add_block(method, body) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/ripper-tags/parser.rb', line 204

def on_method_add_block(method, body)
  return unless method
  if %w[class_eval module_eval].include?(method[2]) && body
    [:class_eval, [
      method[1].is_a?(Array) ? method[1][0] : method[1],
      method[3]
    ], body.last]
  elsif :call == method[0] && body
    # augment the `Class.new/Struct.new` call with associated block
    call = method.dup
    call[4] = body.last
    call
  else
    super
  end
end

#on_module(name, body) ⇒ Object



23
24
25
# File 'lib/ripper-tags/parser.rb', line 23

def on_module(name, body)
  [:module, name, *body.compact]
end

#on_sclass(name, body) ⇒ Object



47
48
49
# File 'lib/ripper-tags/parser.rb', line 47

def on_sclass(name, body)
  [:sclass, name && name.flatten(1), *body.compact]
end

#on_stmts_add(first, *rest) ⇒ Object



19
20
21
# File 'lib/ripper-tags/parser.rb', line 19

def on_stmts_add(first, *rest)
  (first || []) + rest.compact
end

#on_tstring_content(str) ⇒ Object



98
99
100
# File 'lib/ripper-tags/parser.rb', line 98

def on_tstring_content(str)
  str
end

#on_unless_mod(condition, success) ⇒ Object Also known as: on_if_mod



86
87
88
# File 'lib/ripper-tags/parser.rb', line 86

def on_unless_mod(condition, success)
  nil
end

#on_var_ref(*args) ⇒ Object



106
107
108
# File 'lib/ripper-tags/parser.rb', line 106

def on_var_ref(*args)
  on_vcall(*args) || args
end

#on_vcall(name) ⇒ Object



110
111
112
# File 'lib/ripper-tags/parser.rb', line 110

def on_vcall(name)
  [name[0].to_sym] if name[0].to_s =~ /^(private|protected|public)$/
end

#on_xstring_add(first, arg) ⇒ Object



102
103
104
# File 'lib/ripper-tags/parser.rb', line 102

def on_xstring_add(first, arg)
  arg if first.nil?
end