ruby_traverser 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+