ruby_traverser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,152 @@
1
+ module Ruby
2
+ class Node
3
+ module Traversal
4
+ module Misc
5
+ def args?(value, with_block = nil)
6
+ found = 0
7
+ obj = has_a_block?(with_block) ? self.block : self
8
+ args_list = get_args_list(obj)
9
+ return false if !args_list
10
+ args_list.elements.each do |arg|
11
+ argument = retrieve_arg(arg)
12
+ next if !valid_arg?(argument)
13
+ value.each do |v|
14
+ v = v[:array] if v.respond_to?(:has_key?) && v[:array]
15
+ found += 1 if argument == v
16
+ end
17
+ end
18
+ return found == argument_count(value)
19
+ end
20
+
21
+ def argument_count(args)
22
+ args.reject{|arg| !valid_arg?(arg)}.size
23
+ end
24
+
25
+ def valid_arg?(arg)
26
+ arg && arg != {}
27
+ end
28
+
29
+ def has_a_block?(with_block)
30
+ with_block && self.respond_to?(:block)
31
+ end
32
+
33
+ def get_args_list(obj)
34
+ return obj.params if obj.respond_to? :params
35
+ return obj.arguments if obj.respond_to? :arguments
36
+ # return obj if obj.class == Ruby::ArgsList
37
+ end
38
+
39
+ def resolve_arg_wrapper(arg_wrapper)
40
+ return arg_wrapper.arg if arg_wrapper.respond_to? :arg
41
+ return arg_wrapper.param if arg_wrapper.respond_to? :param
42
+ return arg_wrapper if arg_wrapper.class == Ruby::Arg
43
+ arg_wrapper
44
+ end
45
+
46
+ def retrieve_arg(arg_wrapper)
47
+ arg = resolve_arg_wrapper(arg_wrapper)
48
+ argument = get_arg(arg)
49
+ convert_value(argument, arg)
50
+ end
51
+
52
+ def convert_value(value, type = nil)
53
+ type_val = type || value
54
+ case type_val
55
+ when Ruby::Symbol
56
+ value.to_sym
57
+ when Ruby::Integer
58
+ value.to_i
59
+ when Ruby::Float
60
+ value.to_f
61
+ when Ruby::Hash
62
+ type ? get_hash(type) : value
63
+ when Ruby::Array
64
+ type ? get_array(type) : value
65
+ when Ruby::Assoc
66
+ return get_assoc(type)
67
+ else
68
+ value
69
+ end
70
+ end
71
+
72
+ def get_arg(arg)
73
+ get_symbol(arg) || get_assoc(arg) || get_composite(arg) || get_identifier(arg) || get_token(arg) || resolve_arg_wrapper(arg)
74
+ end
75
+
76
+ def get_symbol(arg)
77
+ return nil if !(arg.class == Ruby::Symbol)
78
+ t = get_token(arg)
79
+ t ? t.to_sym : nil
80
+ end
81
+
82
+ def get_composite(arg)
83
+ return nil if !arg.respond_to? :elements
84
+ e = arg.elements
85
+ return get_arg(e[0]) if e.size == 1
86
+ get_hash(e) || get_array(e)
87
+ end
88
+
89
+ def get_array(args)
90
+ return nil if arg.class != Ruby::Array
91
+ arr = []
92
+ args.each do |arg|
93
+ arr << get_arg(arg)
94
+ end
95
+ return arr if !arr.empty?
96
+ nil
97
+ end
98
+
99
+ def get_hash(args)
100
+ return nil if !args.class == Ruby::Hash
101
+ items = args.respond_to?(:elements) ? args.elements : args
102
+ hash = {}
103
+ items.each do |arg|
104
+ hash_val = get_arg(arg)
105
+ hash.merge!(hash_val)
106
+ end
107
+ return hash if !hash.empty?
108
+ nil
109
+ end
110
+
111
+ def get_assoc(arg)
112
+ return nil if !(arg.class == Ruby::Assoc)
113
+ get_hash_item(arg)
114
+ end
115
+
116
+ def get_hash_item(arg)
117
+ return if !arg.respond_to? :key
118
+ key = get_key(arg.key)
119
+ value = get_value(arg.value)
120
+ return {key => value}
121
+ end
122
+
123
+ def get_key(key)
124
+ if key.respond_to? :identifier
125
+ id = get_identifier(key)
126
+ end
127
+ return id.to_sym if key.class == Ruby::Symbol
128
+ return get_token(key) if key.class == Ruby::Variable
129
+ id
130
+ end
131
+
132
+ # Needs rework!
133
+ def get_value(value)
134
+ real_value = get_arg(value)
135
+ convert_value(real_value, value)
136
+ end
137
+
138
+ def get_identifier(arg)
139
+ get_token(arg.identifier) if arg.respond_to? :identifier
140
+ end
141
+
142
+ def get_string(arg)
143
+ get_token(arg.elements[0]) if arg.class == Ruby::String
144
+ end
145
+
146
+ def get_token(arg)
147
+ arg.token if arg.respond_to? :token
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,50 @@
1
+ require 'traversal/module'
2
+ require 'traversal/misc'
3
+ require 'traversal/patch'
4
+
5
+ module Ruby
6
+ class Node
7
+ include Traversal::Module
8
+ include Traversal::Misc
9
+ include Traversal::Patch
10
+
11
+ def has_const?(value)
12
+ if respond_to?(:const)
13
+ if namespace?(value)
14
+ name = value.split('::').last
15
+ return self.const.identifier.token == name
16
+ end
17
+ end
18
+ false
19
+ end
20
+
21
+ def has_block?
22
+ respond_to? :block
23
+ end
24
+
25
+ def has_namespace?(value)
26
+ if respond_to?(:namespace)
27
+ return self.namespace.identifier.token == value
28
+ end
29
+ false
30
+ end
31
+
32
+ def has_identifier?(value)
33
+ if respond_to?(:identifier)
34
+ id = self.identifier
35
+
36
+ if namespace?(value)
37
+ return id.token.to_s == value.to_s if id.respond_to?(:token)
38
+ if id.respond_to?(:identifier)
39
+ name = value.split('::').last
40
+ return id.identifier.token == name
41
+ end
42
+ end
43
+ else
44
+ has_const?(value)
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+
@@ -0,0 +1,52 @@
1
+ module Ruby
2
+ class Node
3
+ module Traversal
4
+ module Module
5
+ def namespace?(full_name)
6
+ if full_name.split('::').size > 1
7
+ namespaces = full_name.split('::')[0..-2]
8
+ namespace = namespaces.join('::')
9
+
10
+ if class_or_module?
11
+ return module_namespace?(namespace)
12
+ end
13
+ end
14
+ true
15
+ end
16
+
17
+ def class_or_module?
18
+ [Ruby::Class, Ruby::Module].include?(self.class)
19
+ end
20
+
21
+ def module_namespace?(namespace)
22
+ namespace == get_full_namespace(get_namespace)
23
+ end
24
+
25
+ def get_namespace
26
+ return self.const.namespace if self.respond_to?(:const)
27
+ self.identifier.namespace
28
+ end
29
+
30
+ def get_full_namespace(ns)
31
+ if ns.respond_to?(:namespace)
32
+ name = ns.identifier.token
33
+ parent_ns = get_full_namespace(ns.namespace)
34
+ name += ('::' + parent_ns) if !parent_ns.empty?
35
+ return name.split('::').reverse.join('::')
36
+ else
37
+ return ns.identifier.token if ns.respond_to?(:identifier)
38
+ ""
39
+ end
40
+ end
41
+
42
+ def superclass?(value)
43
+ if class_or_module?
44
+ ns = get_full_namespace(self.super_class)
45
+ return ns == value
46
+ end
47
+ false
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,83 @@
1
+ module Ruby
2
+ class Node
3
+ module Traversal
4
+ module Patch
5
+ def select(*args, &block)
6
+ result = []
7
+ result << self if matches?(args.dup, &block)
8
+ children.flatten.compact.inject(result) do |result, node|
9
+ if node.class.to_s == 'Symbol'
10
+ return result
11
+ end
12
+ selected = node.select(*args, &block)
13
+ result + selected
14
+ end
15
+ end
16
+
17
+ def children
18
+ (self.try(:elements).to_a || prolog.try(:elements).to_a || []) + nodes
19
+ end
20
+
21
+ def matches?(args, &block)
22
+ conditions = args.last.is_a?(::Hash) ? args.pop : {}
23
+ conditions[:is_a] = args unless args.empty?
24
+
25
+ type_condition = conditions[:is_a][0]
26
+ if type_condition
27
+ return nil if !has_type?(type_condition)
28
+ end
29
+
30
+ res = conditions.inject(!conditions.empty?) do |result, (type, value)|
31
+ block_result = (!block_given? || block.call(self))
32
+ check_res = check_pair(type, value)
33
+ return false if !check_res
34
+ result && check_res && block_result
35
+ end
36
+ res
37
+ end
38
+
39
+ def check_pair(type, value)
40
+ res = case type
41
+ when :is_a
42
+ has_type?(value)
43
+ when :class
44
+ is_instance_of?(value)
45
+ when :token
46
+ has_token?(value)
47
+ when :left_token
48
+ left.has_token?(value)
49
+ when :right_token
50
+ right.has_token?(value)
51
+ when :value
52
+ has_value?(value)
53
+ when :identifier
54
+ has_identifier?(value)
55
+ when :const
56
+ has_const?(value)
57
+ when :block
58
+ has_block?
59
+ when :namespace
60
+ has_namespace?(value)
61
+ when :superclass
62
+ superclass?(value)
63
+ when :args, :params
64
+ args?(value)
65
+ when :block_params
66
+ args?(value, :withblock)
67
+ when :pos, :position
68
+ position?(value)
69
+ when :right_of
70
+ right_of?(value)
71
+ when :left_of
72
+ left_of?(value)
73
+ else
74
+ true
75
+ end
76
+ # puts "check pair type:#{type}, value:#{value} => #{res}, self: #{self.inspect}" if self.class == Ruby::Variable
77
+ res
78
+ end
79
+
80
+ end # Patch
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,79 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ruby_traverser}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kristian Mandrup"]
12
+ s.date = %q{2010-04-27}
13
+ s.description = %q{traverse a ruby code model and optionally mutate it along the way using a nice rubyish DSL}
14
+ s.email = %q{kmandrup@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "LICENSE",
22
+ "README.markdown",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "lib/mutate/api.rb",
26
+ "lib/mutate/replacer.rb",
27
+ "lib/rails/api_wrapper.rb",
28
+ "lib/ruby_traverser.rb",
29
+ "lib/traversal/api/finders.rb",
30
+ "lib/traversal/api/inside.rb",
31
+ "lib/traversal/api/traversal.rb",
32
+ "lib/traversal/misc.rb",
33
+ "lib/traversal/mixin.rb",
34
+ "lib/traversal/module.rb",
35
+ "lib/traversal/patch.rb",
36
+ "ruby_traverser.gemspec",
37
+ "spec/ruby_traverser_spec.rb",
38
+ "spec/spec.opts",
39
+ "spec/spec_helper.rb",
40
+ "test/mutate/mutate_class_test.rb",
41
+ "test/mutate/mutate_test.rb",
42
+ "test/rails_api/gemfile_api.rb",
43
+ "test/test_helper.rb",
44
+ "test/traversal/gemfile_test.rb",
45
+ "test/traversal/ruby_api_traversal_test.rb"
46
+ ]
47
+ s.homepage = %q{http://github.com/kristianmandrup/ruby_trav}
48
+ s.rdoc_options = ["--charset=UTF-8"]
49
+ s.require_paths = ["lib"]
50
+ s.rubygems_version = %q{1.3.6}
51
+ s.summary = %q{traverse and mutate ruby code using a nice DSL}
52
+ s.test_files = [
53
+ "spec/ruby_traverser_spec.rb",
54
+ "spec/spec_helper.rb",
55
+ "test/mutate/mutate_class_test.rb",
56
+ "test/mutate/mutate_test.rb",
57
+ "test/rails_api/gemfile_api.rb",
58
+ "test/test_helper.rb",
59
+ "test/traversal/gemfile_test.rb",
60
+ "test/traversal/ruby_api_traversal_test.rb"
61
+ ]
62
+
63
+ if s.respond_to? :specification_version then
64
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
65
+ s.specification_version = 3
66
+
67
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
68
+ s.add_development_dependency(%q<rspec>, [">= 2.0.0"])
69
+ s.add_runtime_dependency(%q<ripper2ruby>, ["> 0.0.2"])
70
+ else
71
+ s.add_dependency(%q<rspec>, [">= 2.0.0"])
72
+ s.add_dependency(%q<ripper2ruby>, ["> 0.0.2"])
73
+ end
74
+ else
75
+ s.add_dependency(%q<rspec>, [">= 2.0.0"])
76
+ s.add_dependency(%q<ripper2ruby>, ["> 0.0.2"])
77
+ end
78
+ end
79
+
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "RubyTrav" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'ruby_traverser'
4
+ require 'rspec'
5
+ require 'rspec/autorun'
6
+
7
+ Rspec.configure do |c|
8
+ # c.mock_with :rspec
9
+ end
10
+
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'yaml'
3
+
4
+ class TraversalTest < Test::Unit::TestCase
5
+ include TestHelper
6
+
7
+ define_method :"test select Class that inherits from other Class and insert gem statements and a new method def" do
8
+ src = %q{ class Monty < Abc::Blip
9
+ end}
10
+
11
+ def_src = %q{
12
+ def my_fun
13
+ end}
14
+
15
+ def_code = Ripper::RubyBuilder.build(def_src)
16
+ code = Ripper::RubyBuilder.build(src)
17
+ code.inside_class('Monty', :superclass => 'Abc::Blip') do |b|
18
+ assert_equal Ruby::Class, b.class
19
+ gem_abc = b.append_code("gem 'abc'")
20
+ blip = b.append_code("blip")
21
+ gem_123 = gem_abc.append_code("gem '123'")
22
+ gem_123.append_comment("hello")
23
+ my_def = b.append_code(def_src)
24
+
25
+ b.prepend_code("gem '789'")
26
+ puts b.to_ruby
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,90 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'yaml'
3
+
4
+ class TraversalTest < Test::Unit::TestCase
5
+ include TestHelper
6
+
7
+ define_method :"test find gem statement inside group using DSL and then insert new gem statement" do
8
+ src = %q{
9
+ group :test do
10
+ gem 'ripper', :src => 'github'
11
+ gem 'blip'
12
+ end
13
+ }
14
+
15
+ code = Ripper::RubyBuilder.build(src)
16
+
17
+ code.inside_block('group', :args => [:test]) do |b|
18
+ call_node = b.find_call('gem', :args => ['ripper', {:src => 'github'}])
19
+ assert_equal Ruby::Call, call_node.class
20
+ b.append_code("gem 'abc'")
21
+ puts "mutated block:"
22
+ puts b.to_ruby
23
+ end
24
+ end
25
+
26
+ define_method :"test find gem statement inside group using DSL and then replace symbol argument with hash argument" do
27
+ src = %q{
28
+ group :test do
29
+ gem 'ripper', :src
30
+ end
31
+ }
32
+
33
+ code = Ripper::RubyBuilder.build(src)
34
+ code.inside_block('group', :args => [:test]) do |b|
35
+ call_node = b.find_call('gem', :args => ['ripper'])
36
+ assert_equal Ruby::Call, call_node.class
37
+ call_node.replace(:arg => :src , :replace_code => "{:src => 'unknown'}")
38
+ puts b.to_ruby
39
+ end
40
+ end
41
+
42
+ define_method :"test find gem statement inside group using DSL and then replace matching hash with new hash" do
43
+ src = %q{
44
+ group :test do
45
+ gem 'ripper', :src => 'blip'
46
+ end
47
+ }
48
+
49
+ code = Ripper::RubyBuilder.build(src)
50
+ code.inside_block('group', :args => [:test]) do |b|
51
+ call_node = b.find_call('gem', :args => ['ripper'])
52
+ assert_equal Ruby::Call, call_node.class
53
+ call_node.replace(:arg => {:src => 'blip'} , :replace_code => "{:src => 'unknown'}")
54
+ puts b.to_ruby
55
+ end
56
+ end
57
+
58
+ define_method :"test find assignment in method definition and replace value of right side" do
59
+ src = %q{
60
+ def hello_world(a)
61
+ my_var = 2
62
+ end
63
+ }
64
+
65
+ code = Ripper::RubyBuilder.build(src)
66
+
67
+ code.inside_def('hello_world', :params => ['a']) do |b|
68
+ # call_node = b.find_call('gem', :args => ['ripper', {:src => 'github'}], :verbose => true)
69
+ call_node = b.find_assignment('my_var')
70
+ assert_equal Ruby::Assignment, call_node.class
71
+
72
+ call_node.replace(:value => "3")
73
+ puts b.to_ruby
74
+ end
75
+ end
76
+
77
+ define_method :"test select Class that inherits from other Class and insert new method def" do
78
+ src = %q{
79
+ class Monty < Abc::Blip
80
+ end
81
+ }
82
+ code = Ripper::RubyBuilder.build(src)
83
+ code.find_class('Monty', :superclass => 'Abc::Blip') do |b|
84
+ assert_equal Ruby::Class, b.class
85
+ b.append_code("gem 'abc'")
86
+ puts b.to_ruby
87
+ end
88
+ end
89
+
90
+ end
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'yaml'
3
+
4
+ require 'rails/api_wrapper'
5
+
6
+ class TraversalTest < Test::Unit::TestCase
7
+ include TestHelper
8
+
9
+ define_method :"test find gem statement inside group using DSL and then insert new gem statement" do
10
+ src = %q{
11
+ group :test do
12
+ gem 'ripper', :src => 'github'
13
+ gem 'blip'
14
+ end
15
+ }
16
+
17
+ code = Ripper::RubyBuilder.build(src)
18
+
19
+ code.extend(RubyAPI::Rails::Gemfile)
20
+ code.inside_group :test do |b|
21
+ b.add_gem 'cucumber' if !b.find_gem 'cucumber'
22
+ b.replace_gem 'blip', 'blap'
23
+ end
24
+ puts code.to_ruby
25
+ end
26
+ end
27
+
@@ -0,0 +1,53 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'ripper/ruby_builder'
4
+ require 'ruby_traverser'
5
+ require 'ripper/event_log'
6
+ require 'test/unit'
7
+ require 'pp'
8
+ require 'highlighters/ansi'
9
+
10
+ module TestHelper
11
+ def build(src, filename = nil)
12
+ Ripper::RubyBuilder.build(src, filename)
13
+ end
14
+
15
+ def sexp(src)
16
+ pp Ripper::SexpBuilder.new(src).parse
17
+ end
18
+
19
+ def log(src)
20
+ Ripper::EventLog.out(src)
21
+ end
22
+
23
+ def assert_build(src)
24
+ expr = build(src)
25
+ assert_equal src, expr.to_ruby(true)
26
+ assert_equal src, expr.src(true)
27
+ # expr.all_nodes.each { |node| assert_equal Ruby::Program, node.root.class }
28
+ yield(expr) if block_given?
29
+ expr
30
+ end
31
+
32
+ def assert_node(node, assertions)
33
+ node = node.first if node.is_a?(Array)
34
+ assertions.each do |type, value|
35
+ case type
36
+ when :is_a
37
+ assert node.is_a?(value)
38
+ when :class
39
+ assert_equal value, node.class
40
+ when :pos, :position
41
+ assert_position(value, node)
42
+ end
43
+ end
44
+ end
45
+
46
+ def assert_position(position, node)
47
+ node = node.first if node.is_a?(Array)
48
+ assert_equal position, node.position.to_a
49
+ end
50
+ end
51
+
52
+
53
+