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



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

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

#on_aref_field(*args) ⇒ Object



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

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

#on_args_add(sub, arg) ⇒ Object



240
241
242
243
244
245
246
# File 'lib/ripper-tags/parser.rb', line 240

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

#on_array(args) ⇒ Object



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

def on_array(args)
  if args.is_a?(Array) && args[0] == :args
    args[1..-1]
  end
end

#on_assign(lhs, rhs) ⇒ Object



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

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_assoc_new(key, value) ⇒ Object

Otherwise hashes and keyword arguments turn into a list of their keys only



270
271
272
# File 'lib/ripper-tags/parser.rb', line 270

def on_assoc_new(key, value)
  [:assoc, key, value]
end

#on_binary(*args) ⇒ Object



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

def on_binary(*args)
end

#on_bodystmt(*args) ⇒ Object



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

def on_bodystmt(*args)
  args
end

#on_call(lhs, op, rhs) ⇒ Object



150
151
152
153
154
# File 'lib/ripper-tags/parser.rb', line 150

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



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

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

#on_command(name, *args) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/ripper-tags/parser.rb', line 68

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",
       "public_class_method", "private_class_method",
       "public", "protected", "private",
       /^attr_(accessor|reader|writer)$/
    on_method_add_arg([:fcall, name], args[0])
  when "delegate"
    on_delegate(*Array(args[0])[1..-1])
  when "def_delegator", "def_instance_delegator"
    on_def_delegator(*args[0][1..-1])
  when "def_delegators", "def_instance_delegators"
    on_def_delegators(*args[0][1..-1])
  end
end

#on_command_call(*args) ⇒ Object

handle ‘Class.new arg` call without parens



226
227
228
229
230
231
232
233
234
# File 'lib/ripper-tags/parser.rb', line 226

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



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

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



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

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

#on_def_delegator(*args) ⇒ Object



294
295
296
297
# File 'lib/ripper-tags/parser.rb', line 294

def on_def_delegator(*args)
  name, lineno = args.last
  [:def, name, lineno]
end

#on_def_delegators(*args) ⇒ Object



299
300
301
302
303
304
# File 'lib/ripper-tags/parser.rb', line 299

def on_def_delegators(*args)
  _target, *names = args
  names.map do |name, lineno|
    [:def, name, lineno]
  end
end

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



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

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

#on_delegate(*args) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/ripper-tags/parser.rb', line 274

def on_delegate(*args)
  method_names = args.select { |arg| arg.first.is_a? String }
  options = args.select { |arg| arg.first.is_a?(Array) && arg.first.first == :assoc }.flatten(1)
  options = Hash[options.map { |_assoc, key, val| [key[0], val[0]] if key }.compact]

  target = options["to:"] || options["to"] # When using hashrocket syntax there is no ':'
  prefix = options["prefix:"] || options["prefix"]
  method_prefix = if prefix.is_a?(Array) && prefix.first == "true"
                    "#{target}_"
                  elsif prefix.is_a? String
                    "#{prefix}_"
                  else
                    ""
                  end

  method_names.map do |name, lineno|
    [:def, "#{method_prefix}#{name}", lineno]
  end
end

#on_do_block(*args) ⇒ Object



248
249
250
# File 'lib/ripper-tags/parser.rb', line 248

def on_do_block(*args)
  args
end

#on_dyna_symbol(*args) ⇒ Object



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

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

#on_fcall(*args) ⇒ Object



236
237
238
# File 'lib/ripper-tags/parser.rb', line 236

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

#on_field(lhs, op, rhs) ⇒ Object



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

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

#on_hash(args) ⇒ Object



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

def on_hash(args)
  return unless args

  args.select { |arg| arg.is_a?(Array) && arg[0] == :assoc }.map { |_assoc, k, _v| k }
end

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



89
90
91
92
# File 'lib/ripper-tags/parser.rb', line 89

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

#on_method_add_arg(call, args) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/ripper-tags/parser.rb', line 156

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 "public_class_method", "private_class_method", "private", "public", "protected"
      access = name.sub("_class_method", "")

      if args[1][1] == 'self'
        klass = 'self'
        method_name = args[1][2]
      else
        klass = nil
        method_name = args[1][1]
      end

      [:def_with_access, klass, method_name, access, 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



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/ripper-tags/parser.rb', line 252

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



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

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

#on_sclass(name, body) ⇒ Object



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

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

#on_stmts_add(first, *rest) ⇒ Object



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

def on_stmts_add(first, *rest)
  return if first == :~
  Array(first) + rest.compact
end

#on_string_add(*args) ⇒ Object



123
124
125
# File 'lib/ripper-tags/parser.rb', line 123

def on_string_add(*args)
  [args[1], lineno]
end

#on_string_dvarObject



130
131
132
# File 'lib/ripper-tags/parser.rb', line 130

def on_string_dvar(*)
  :string_embexpr
end

#on_string_embexprObject



127
128
129
# File 'lib/ripper-tags/parser.rb', line 127

def on_string_embexpr(*)
  :string_embexpr
end

#on_string_literal(*args) ⇒ Object



133
134
135
136
# File 'lib/ripper-tags/parser.rb', line 133

def on_string_literal(*args)
  args = args.flatten
  args unless args.include?(:string_embexpr)
end

#on_tstring_content(str) ⇒ Object



119
120
121
# File 'lib/ripper-tags/parser.rb', line 119

def on_tstring_content(str)
  str
end

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



95
96
97
# File 'lib/ripper-tags/parser.rb', line 95

def on_unless_mod(condition, success)
  nil
end

#on_var_ref(*args) ⇒ Object



142
143
144
# File 'lib/ripper-tags/parser.rb', line 142

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

#on_vcall(name) ⇒ Object



146
147
148
# File 'lib/ripper-tags/parser.rb', line 146

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

#on_xstring_add(first, arg) ⇒ Object



138
139
140
# File 'lib/ripper-tags/parser.rb', line 138

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