Class: Sexp

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_best_practices/core/visitable_sexp.rb

Instance Method Summary collapse

Instance Method Details

#argumentsSexp

Get arguments of call node.

s(:attrasgn,
  s(:call, nil, :post, s(:arglist)),
  :user=,
  s(:arglist,
    s(:call, nil, :current_user, s(:arglist))
  )
)
    => s(:arglist, s(:call, nil, :current_user, s(:arglist)))

s(:call,
  s(:call, nil, :username, s(:arglist)),
  :==,
  s(:arglist, s(:str, ""))
)
    => s(:arglist, s(:str, ""))


250
251
252
253
254
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 250

def arguments
  if [:attrasgn, :call].include? node_type
    self[3]
  end
end

#base_classSexp

Get the base class of the class node.

s(:class, :User, s(:colon2, s(:const, :ActiveRecord), :Base), s(:scope))
    => s(:colon2, s(:const, :ActiveRecord), :Base)


150
151
152
153
154
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 150

def base_class
  if :class == node_type
    self[2]
  end
end

#bodySexp

Get body of iter, class and defn node.

s(:iter,
  s(:call, nil, :resources, s(:arglist, s(:lit, :posts))),
  nil,
  s(:call, nil, :resources, s(:arglist, s(:lit, :comments)))
)
    => s(:call, nil, :resources, s(:arglist, s(:lit, :comments)))

s(:class, :User, nil,
  s(:scope,
    s(:block,
      s(:defn, :login, s(:args), s(:scope, s(:block, s(:nil)))),
      s(:defn, :email, s(:args), s(:scope, s(:block, s(:nil))))
    )
  )
)
    => s(:block,
         s(:defn, :login, s(:args), s(:scope, s(:block, s(:nil)))),
         s(:defn, :email, s(:args), s(:scope, s(:block, s(:nil))))
       )

s(:defn, :fullname, s(:args),
  s(:scope,
    s(:block,
      s(:call,
        s(:call,
          s(:call, nil, :first_name, s(:arglist)),
          :+,
          s(:arglist,
            s(:call, nil, :last, s(:arglist))
          )
        ),
        :+,
        s(:arglist,
          s(:call, nil, :name, s(:arglist))
        )
      )
    )
  )
)
    => s(:block,
         s(:call,
           s(:call,
             s(:call, nil, :first_name, s(:arglist)),
             :+,
             s(:arglist,
               s(:call, nil, :last, s(:arglist))
             )
           ),
           :+,
           s(:arglist,
             s(:call, nil, :name, s(:arglist))
           )
         )
       )


386
387
388
389
390
391
392
393
394
395
396
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 386

def body
  if :iter == node_type
    self[3]
  elsif :class == node_type
    self[3][1]
  elsif :module == node_type
    self[2][1]
  elsif :defn == node_type
    self[3][1]
  end
end

#childrenArray

return child nodes of a sexp node.

s(:call, nil, :puts,
  s(:arglist, s(:str, "hello "), s(:str, "world"))
)
  => [s(:arglist, s(:str, "hello "), s(:str, "world"))]


27
28
29
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 27

def children
  find_all { | sexp | Sexp === sexp }
end

#class_nameSymbol

Get the class name of the class node.

s(:class, :User, nil, s(:scope))
    => :User


138
139
140
141
142
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 138

def class_name
  if :class == node_type
    self[1]
  end
end

#conditional_statementSexp

Get the conditional statement of if node.

s(:if,
  s(:call,
    s(:call, nil, :current_user, s(:arglist)),
    :present?,
    s(:arglist)
  ),
  s(:call, nil, :puts,
    s(:arglist,
      s(:call,
        s(:call, nil, :current_user, s(:arglist)),
        :login,
        s(:arglist)
      )
    )
  ),
  nil
)
    => s(:call, s(:call, nil, :current_user, s(:arglist)), :present?, s(:arglist))


278
279
280
281
282
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 278

def conditional_statement
  if :if == node_type
    self[1]
  end
end

#false_nodeSexp

Get the body node when conditional statement is false.

s(:if,
  s(:call, s(:call, nil, :current_user, s(:arglist)), :login?, s(:arglist)),
  s(:call, s(:call, nil, :current_user, s(:arglist)), :login, s(:arglist)),
  s(:call, s(:call, nil, :current_user, s(:arglist)), :email, s(:arglist))
)
    => s(:call, s(:call, nil, :current_user, s(:arglist)), :email, s(:arglist))


310
311
312
313
314
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 310

def false_node
  if :if == node_type
    self[3]
  end
end

#grep_node(options) ⇒ Object

grep all the recursive child nodes with conditions, and yield the first match node.

options is the grep conditions, like

:node_type => :call,
:subject => s(:const, Post),
:message => [:find, :new],
:arguments => s(:arglist)

the condition key is one of :node_type, :subject, :message or :arguments, the condition value can be Symbol, Array or Sexp.



80
81
82
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 80

def grep_node(options)
  grep_nodes(options) { |node| return node }
end

#grep_nodes(options) ⇒ Object

grep all the recursive child nodes with conditions, and yield each match node.

options is the grep conditions, like

:node_type => :call,
:subject => s(:const, Post),
:message => [:find, :new],
:arguments => s(:arglist)

the condition key is one of :node_type, :subject, :message or :arguments, the condition value can be Symbol, Array or Sexp.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 52

def grep_nodes(options)
  node_type = options[:node_type]
  subject = options[:subject]
  message = options[:message]
  arguments = options[:arguments]
  self.recursive_children do |child|
    if (!node_type || (node_type.is_a?(Array) ? node_type.include?(child.node_type) : node_type == child.node_type)) &&
       (!subject || (subject.is_a?(Array) ? subject.include?(child.subject) : subject == child.subject)) &&
       (!message || (message.is_a?(Array) ? message.include?(child.message) : message == child.message)) &&
       (!arguments || (arguments.is_?(Array) ? arguments.include?(child.arguments) : arguments == child.arguments))
      yield child
    end
  end
end

#grep_nodes_count(options) ⇒ Integer

grep all the recursive child nodes with conditions, and get the count of match nodes.



88
89
90
91
92
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 88

def grep_nodes_count(options)
  count = 0
  grep_nodes(options) { |node| count += 1 }
  count
end

#left_valueSymbol

Get the left value of the lasgn or iasgn node.

s(:lasgn,
  :user,
  s(:call,
    s(:call, nil, :params, s(:arglist)),
    :[],
    s(:arglist, s(:lit, :user))
  )
)
    => :user

s(:iasgn,
  :@user,
  s(:call,
    s(:call, nil, :params, s(:arglist)),
    :[],
    s(:arglist, s(:lit, :user))
  )
)
    => :@user


179
180
181
182
183
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 179

def left_value
  if [:lasgn, :iasgn].include? node_type
    self[1]
  end
end

#messageSymbol

Get the message of attrasgn and call node.

s(:attrasgn,
  s(:call, nil, :user, s(:arglist)),
  :name=,
  s(:arglist,
    s(:call,
      s(:call, nil, :params, s(:arglist)),
      :[],
      s(:arglist, s(:lit, :name))
    )
  )
)
    => :name=

s(:call, nil, :has_many, s(:arglist, s(:lit, :projects)))
    => :has_many


225
226
227
228
229
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 225

def message
  if [:attrasgn, :call].include? node_type
    self[2]
  end
end

#method_nameSymbol

Get the method name of defn node.

s(:defn, :show, s(:args), s(:scope, s(:block, s(:nil))))
    => :show


322
323
324
325
326
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 322

def method_name
  if :defn == node_type
    self[1]
  end
end

#prepare(visitor) ⇒ Object

prepare current node.



8
9
10
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 8

def prepare(visitor)
  visitor.prepare(self)
end

#recursive_childrenObject

recursively find all child nodes, and yeild each child node.



32
33
34
35
36
37
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 32

def recursive_children
  children.each do |child|
    yield child
    child.recursive_children { |c| yield c }
  end
end

#review(visitor) ⇒ Object

prepare current node.



15
16
17
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 15

def review(visitor)
  visitor.review(self)
end

#right_valueSexp

Get the right value of lasgn and iasgn node.

s(:lasgn,
  :user,
  s(:call, nil, :current_user, s(:arglist))
)
    => s(:call, nil, :current_user, s(:arglist))

s(:iasgn,
  :@user,
  s(:call, nil, :current_user, s(:arglist))
)
    => s(:call, nil, :current_user, s(:arglist))


200
201
202
203
204
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 200

def right_value
  if [:lasgn, :iasgn].include? node_type
    self[2]
  end
end

#subjectSexp

Get subject of attrasgan, call and iter node.

s(:attrasgn,
  s(:call, nil, :user, s(:arglist)),
  :name=,
  s(:arglist,
    s(:call,
      s(:call, nil, :params, s(:arglist)),
      :[],
      s(:arglist, s(:lit, :name))
    )
  )
)
    => s(:call, nil, :user, s(:arglist))

s(:call,
  s(:call, nil, :user, s(:arglist)),
  :name,
  s(:arglist)
)
    => s(:call, nil, :user, s(:arglist))

s(:iter,
  s(:call, s(:ivar, :@users), :each, s(:arglist)),
  s(:lasgn, :user),
  s(:call, nil, :p,
    s(:arglist, s(:lvar, :user))
  )
)
    => s(:call, :s(:ivar, ;@users), :each, s(:arglist))


126
127
128
129
130
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 126

def subject
  if [:attrasgn, :call, :iter].include? node_type
    self[1]
  end
end

#to_s(options = {}) ⇒ String

to_s for lvar, ivar, lit, const, array, hash, and colon2 node.



403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 403

def to_s(options={})
  case node_type
  when :true, :false, :nil
    self[0].to_s
  when :ivar
    options[:remove_at] ? self[1].to_s[1..-1] : self[1].to_s
  when :lvar, :str, :lit, :const
    self[1].to_s
  when :array
    "[\"#{self.children.collect(&:to_s).join('", "')}\"]"
  when :hash
    key_value = false # false is key, true is value
    result = ['{']
    children.each do |child|
      if [:true, :false, :nil, :array, :hash].include? child.node_type
        result << "#{child}"
      else
        result << "\"#{child}\""
      end
      result << (key_value ? ", " : " => ")
      key_value = !key_value
    end
    result.join("").sub(/, $/, '') + '}'
  when :colon2
    "#{self[1]}::#{self[2]}"
  else
    ""
  end
end

#true_nodeSexp

Get the body node when conditional statement is true.

s(:if,
  s(:call, s(:call, nil, :current_user, s(:arglist)), :login?, s(:arglist)),
  s(:call, s(:call, nil, :current_user, s(:arglist)), :login, s(:arglist)),
  s(:call, s(:call, nil, :current_user, s(:arglist)), :email, s(:arglist))
)
    => s(:call, s(:call, nil, :current_user, s(:arglist)), :login, s(:arglist))


294
295
296
297
298
# File 'lib/rails_best_practices/core/visitable_sexp.rb', line 294

def true_node
  if :if == node_type
    self[2]
  end
end