mirrors 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +23 -0
- data/LICENSE.txt +59 -0
- data/README.md +1 -0
- data/asdfasdf.rb +53 -0
- data/bin/bundler +17 -0
- data/bin/byebug +17 -0
- data/bin/testunit +8 -0
- data/circle.yml +6 -0
- data/dev.yml +6 -0
- data/lib/mirrors.rb +150 -0
- data/lib/mirrors/class_mirror.rb +197 -0
- data/lib/mirrors/class_mixin.rb +11 -0
- data/lib/mirrors/field_mirror.rb +24 -0
- data/lib/mirrors/field_mirror/class_variable_mirror.rb +23 -0
- data/lib/mirrors/field_mirror/constant_mirror.rb +34 -0
- data/lib/mirrors/field_mirror/instance_variable_mirror.rb +23 -0
- data/lib/mirrors/hook.rb +33 -0
- data/lib/mirrors/index/indexer.rb +6 -0
- data/lib/mirrors/index/marker.rb +40 -0
- data/lib/mirrors/invoke.rb +29 -0
- data/lib/mirrors/method_mirror.rb +206 -0
- data/lib/mirrors/mirror.rb +37 -0
- data/lib/mirrors/object_mirror.rb +25 -0
- data/lib/mirrors/package_inference.rb +164 -0
- data/lib/mirrors/package_inference/class_to_file_resolver.rb +66 -0
- data/lib/mirrors/package_mirror.rb +33 -0
- data/lib/mirrors/visitors/disasm_visitor.rb +11 -0
- data/lib/mirrors/visitors/iseq_visitor.rb +84 -0
- data/lib/mirrors/visitors/references_visitor.rb +58 -0
- data/lib/mirrors/visitors/yasmdata.rb +212 -0
- data/lol.rb +35 -0
- data/mirrors.gemspec +19 -0
- data/test/fixtures/class.rb +29 -0
- data/test/fixtures/field.rb +9 -0
- data/test/fixtures/method.rb +15 -0
- data/test/fixtures/object.rb +5 -0
- data/test/fixtures/reflect.rb +14 -0
- data/test/mirrors/class_mirror_test.rb +87 -0
- data/test/mirrors/field_mirror_test.rb +125 -0
- data/test/mirrors/iseq_visitor_test.rb +56 -0
- data/test/mirrors/marker_test.rb +48 -0
- data/test/mirrors/method_mirror_test.rb +62 -0
- data/test/mirrors/object_mirror_test.rb +16 -0
- data/test/mirrors/package_inference_test.rb +31 -0
- data/test/mirrors/references_visitor_test.rb +30 -0
- data/test/mirrors_test.rb +38 -0
- data/test/test_helper.rb +12 -0
- metadata +137 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'mirrors/visitors/disasm_visitor'
|
3
|
+
|
4
|
+
module Mirrors
|
5
|
+
class ISeqVisitorTest < MiniTest::Test
|
6
|
+
class CountingVisitor < Mirrors::ISeqVisitor
|
7
|
+
attr_reader :count
|
8
|
+
def initialize
|
9
|
+
@count = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def visit(_bytecode)
|
13
|
+
@count += 1
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_all_methods
|
18
|
+
class_count = 0
|
19
|
+
method_count = 0
|
20
|
+
bytecode_count = 0
|
21
|
+
smallest = 1024
|
22
|
+
smallest_method = nil
|
23
|
+
largest = 0
|
24
|
+
largest_method = nil
|
25
|
+
|
26
|
+
Mirrors.classes.each do |clazz|
|
27
|
+
clazz.methods.each do |meth|
|
28
|
+
visitor = CountingVisitor.new
|
29
|
+
visitor.call(meth)
|
30
|
+
bytecode_count += visitor.count
|
31
|
+
|
32
|
+
if visitor.count > largest
|
33
|
+
largest = visitor.count
|
34
|
+
largest_method = meth
|
35
|
+
end
|
36
|
+
|
37
|
+
if visitor.count < smallest && visitor.count > 0
|
38
|
+
smallest = visitor.count
|
39
|
+
smallest_method = meth
|
40
|
+
end
|
41
|
+
bytecode_count += visitor.count
|
42
|
+
method_count += 1
|
43
|
+
end
|
44
|
+
class_count += 1
|
45
|
+
end
|
46
|
+
assert(class_count >= 788)
|
47
|
+
assert(method_count >= 4782)
|
48
|
+
assert(bytecode_count >= 47308)
|
49
|
+
|
50
|
+
puts "Walked #{class_count} classes with #{method_count} methods and #{bytecode_count} bytecodes."
|
51
|
+
puts "Largest method #{largest_method.defining_class.name}.#{largest_method.name}, #{largest} bytecodes."
|
52
|
+
puts "Smallest method #{smallest_method.defining_class.name}.#{smallest_method.name}, #{smallest} bytecodes."
|
53
|
+
puts "Average method #{bytecode_count / method_count} bytecodes."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Mirrors
|
4
|
+
class MarkerTest < MiniTest::Test
|
5
|
+
def setup
|
6
|
+
@class_marker = Marker.new(type: Marker::TYPE_CLASS_REFERENCE, message: 'Class', file: __FILE__, line: __LINE__)
|
7
|
+
@field_marker = Marker.new(type: Marker::TYPE_FIELD_REFERENCE, message: 'Field', file: __FILE__, line: __LINE__)
|
8
|
+
@method_marker = Marker.new(type: Marker::TYPE_METHOD_REFERENCE, message: 'Method', file: __FILE__, line: __LINE__)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_class_marker
|
13
|
+
assert_equal(Marker::TYPE_CLASS_REFERENCE, @class_marker.type)
|
14
|
+
assert_equal('Class', @class_marker.message)
|
15
|
+
assert_equal(__FILE__, @class_marker.file)
|
16
|
+
assert_equal(6, @class_marker.line)
|
17
|
+
assert_equal(Marker::NO_COLUMN, @class_marker.start_column)
|
18
|
+
assert_equal(Marker::NO_COLUMN, @class_marker.end_column)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_field_marker
|
22
|
+
assert_equal(Marker::TYPE_FIELD_REFERENCE, @field_marker.type)
|
23
|
+
assert_equal('Field', @field_marker.message)
|
24
|
+
assert_equal(__FILE__, @field_marker.file)
|
25
|
+
assert_equal(7, @field_marker.line)
|
26
|
+
assert_equal(Marker::NO_COLUMN, @field_marker.start_column)
|
27
|
+
assert_equal(Marker::NO_COLUMN, @field_marker.end_column)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_method_marker
|
31
|
+
assert_equal(Marker::TYPE_METHOD_REFERENCE, @method_marker.type)
|
32
|
+
assert_equal('Method', @method_marker.message)
|
33
|
+
assert_equal(__FILE__, @method_marker.file)
|
34
|
+
assert_equal(8, @method_marker.line)
|
35
|
+
assert_equal(Marker::NO_COLUMN, @method_marker.start_column)
|
36
|
+
assert_equal(Marker::NO_COLUMN, @method_marker.end_column)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_hash_and_equal
|
40
|
+
m1 = @class_marker
|
41
|
+
m2 = @class_marker.dup
|
42
|
+
assert(m1.object_id != m2.object_id)
|
43
|
+
assert(m1 == m2)
|
44
|
+
assert(m1.eql?(m2))
|
45
|
+
assert_equal(m1.hash, m2.hash)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Mirrors
|
4
|
+
class MethodMirrorTest < MiniTest::Test
|
5
|
+
def setup
|
6
|
+
@cm = Mirrors.reflect(MethodSpecFixture)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_source_location
|
11
|
+
@f = MethodSpecFixture
|
12
|
+
m = MethodSpecFixture.instance_method(:source_location)
|
13
|
+
@m = Mirrors.reflect(m)
|
14
|
+
|
15
|
+
assert_equal(@f.new.source_location[0], @m.file)
|
16
|
+
assert_equal(@f.new.source_location[1] - 2, @m.line)
|
17
|
+
assert_equal(@f.new.source_location[2], @m.selector)
|
18
|
+
assert_equal(@f.new.source_location[3].name, @m.defining_class.name)
|
19
|
+
assert_includes(@m.source, '[__FILE__, __LINE__, __method__.to_s, self.class]')
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_arguments
|
23
|
+
m = Mirrors.reflect(method(:method_b))
|
24
|
+
assert_equal(%w(a b bb args block), m.arguments)
|
25
|
+
assert_equal("block", m.block_argument)
|
26
|
+
assert_equal(%w(a), m.required_arguments)
|
27
|
+
assert_equal(%w(b bb), m.optional_arguments)
|
28
|
+
assert_equal('args', m.splat_argument)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_public_method
|
32
|
+
m = @cm.method(:method_p_public)
|
33
|
+
assert(m.public?)
|
34
|
+
refute(m.protected?)
|
35
|
+
refute(m.private?)
|
36
|
+
assert_equal(:public, m.visibility)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_protected_method
|
40
|
+
m = @cm.method(:method_p_protected)
|
41
|
+
refute(m.public?)
|
42
|
+
assert(m.protected?)
|
43
|
+
refute(m.private?)
|
44
|
+
assert_equal(:protected, m.visibility)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_private_method
|
48
|
+
m = @cm.method(:method_p_private)
|
49
|
+
refute(m.public?)
|
50
|
+
refute(m.protected?)
|
51
|
+
assert(m.private?)
|
52
|
+
assert_equal(:private, m.visibility)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def method_b(a, b = 1, bb = 2, *args, &block)
|
58
|
+
to_s
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Mirrors
|
4
|
+
class ObjectMirrorTest < MiniTest::Test
|
5
|
+
def setup
|
6
|
+
@o = ObjectFixture.new
|
7
|
+
@m = Mirrors.reflect(@o)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_variables
|
12
|
+
vars = @m.variables
|
13
|
+
assert_equal(["@ivar"], vars.map(&:name))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Mirrors
|
4
|
+
class PackageInferenceTest < MiniTest::Test
|
5
|
+
|
6
|
+
def test_core
|
7
|
+
assert_equal('core', PackageInference.infer_from(Object))
|
8
|
+
assert_equal('core', PackageInference.infer_from(Errno::EAGAIN))
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_stdlib
|
12
|
+
require 'digest'
|
13
|
+
assert_equal('core:stdlib', PackageInference.infer_from(Digest))
|
14
|
+
assert_equal('core:stdlib', PackageInference.infer_from(Digest::SHA256))
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_gems
|
18
|
+
assert_equal('gems:minitest', PackageInference.infer_from(MiniTest))
|
19
|
+
assert_equal('gems:minitest', PackageInference.infer_from(MiniTest::Test))
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_application
|
23
|
+
assert_equal('application', PackageInference.infer_from(Mirrors))
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_unknown_eval
|
27
|
+
eval('class Unknown; end')
|
28
|
+
assert_equal('unknown:eval', PackageInference.infer_from(Unknown))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'mirrors/index/marker'
|
3
|
+
|
4
|
+
module Mirrors
|
5
|
+
class ReferencesVisitorTest < MiniTest::Test
|
6
|
+
class Victim
|
7
|
+
def lol
|
8
|
+
@ivar += 1 # touch one of the ivars
|
9
|
+
to_s # send to_s
|
10
|
+
Kernel.exit # reference another class
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_victim_class
|
15
|
+
method = Victim.reflect.methods.first
|
16
|
+
refs = method.references
|
17
|
+
assert_equal(4, refs.size)
|
18
|
+
c1 = Marker.new(type: Marker::TYPE_CLASS_REFERENCE, message: :Kernel, file: __FILE__, line: 10)
|
19
|
+
m1 = Marker.new(type: Marker::TYPE_METHOD_REFERENCE, message: :to_s, file: __FILE__, line: 9)
|
20
|
+
m2 = Marker.new(type: Marker::TYPE_METHOD_REFERENCE, message: :exit, file: __FILE__, line: 10)
|
21
|
+
f1 = Marker.new(type: Marker::TYPE_FIELD_REFERENCE, message: :@ivar, file: __FILE__, line: 8)
|
22
|
+
|
23
|
+
assert_equal('lol', method.selector) # ensure that we have the right method
|
24
|
+
assert(refs.include?(c1))
|
25
|
+
assert(refs.include?(m1))
|
26
|
+
assert(refs.include?(m2))
|
27
|
+
assert(refs.include?(f1))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class MirrorsTest < MiniTest::Test
|
4
|
+
def test_modules
|
5
|
+
modules = Mirrors.modules.collect(&:name)
|
6
|
+
assert_includes(modules, "ReflectModule")
|
7
|
+
refute_includes(modules, "ReflectClass")
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_classes
|
11
|
+
classes = Mirrors.classes.collect(&:name)
|
12
|
+
refute_includes(classes, "ReflectModule")
|
13
|
+
assert_includes(classes, "ReflectClass")
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_instances_of
|
17
|
+
klass1 = Class.new
|
18
|
+
klass2 = Class.new(klass1)
|
19
|
+
inst1 = klass1.new
|
20
|
+
inst2 = klass2.new
|
21
|
+
instances = Mirrors.instances_of(klass1).map(&:name)
|
22
|
+
assert_includes(instances, inst1.inspect)
|
23
|
+
refute_includes(instances, inst2.inspect)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_object_by_id
|
27
|
+
o = Object.new
|
28
|
+
assert_equal(o.inspect, Mirrors.object_by_id(o.object_id).name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_implementations_of
|
32
|
+
l = Mirrors.implementations_of("unique_reflect_fixture_method")
|
33
|
+
assert_equal(Array, l.class)
|
34
|
+
assert_equal(1, l.size)
|
35
|
+
assert_equal("unique_reflect_fixture_method", l.first.selector)
|
36
|
+
assert_equal("ReflectClass", l.first.defining_class.name)
|
37
|
+
end
|
38
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('..', __FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
3
|
+
|
4
|
+
require 'mirrors'
|
5
|
+
|
6
|
+
require 'fixtures/reflect'
|
7
|
+
require 'fixtures/class'
|
8
|
+
require 'fixtures/object'
|
9
|
+
require 'fixtures/method'
|
10
|
+
require 'fixtures/field'
|
11
|
+
|
12
|
+
require 'minitest/autorun'
|
metadata
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mirrors
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Burke Libbey
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: byebug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 9.0.6
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 9.0.6
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: method_source
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.8'
|
55
|
+
description: Provides a number of specs and classes that document a mirror API for
|
56
|
+
Ruby.
|
57
|
+
email:
|
58
|
+
- burke.libbey@shopify.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rubocop.yml"
|
65
|
+
- Gemfile
|
66
|
+
- Gemfile.lock
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- asdfasdf.rb
|
70
|
+
- bin/bundler
|
71
|
+
- bin/byebug
|
72
|
+
- bin/testunit
|
73
|
+
- circle.yml
|
74
|
+
- dev.yml
|
75
|
+
- lib/mirrors.rb
|
76
|
+
- lib/mirrors/class_mirror.rb
|
77
|
+
- lib/mirrors/class_mixin.rb
|
78
|
+
- lib/mirrors/field_mirror.rb
|
79
|
+
- lib/mirrors/field_mirror/class_variable_mirror.rb
|
80
|
+
- lib/mirrors/field_mirror/constant_mirror.rb
|
81
|
+
- lib/mirrors/field_mirror/instance_variable_mirror.rb
|
82
|
+
- lib/mirrors/hook.rb
|
83
|
+
- lib/mirrors/index/indexer.rb
|
84
|
+
- lib/mirrors/index/marker.rb
|
85
|
+
- lib/mirrors/invoke.rb
|
86
|
+
- lib/mirrors/method_mirror.rb
|
87
|
+
- lib/mirrors/mirror.rb
|
88
|
+
- lib/mirrors/object_mirror.rb
|
89
|
+
- lib/mirrors/package_inference.rb
|
90
|
+
- lib/mirrors/package_inference/class_to_file_resolver.rb
|
91
|
+
- lib/mirrors/package_mirror.rb
|
92
|
+
- lib/mirrors/visitors/disasm_visitor.rb
|
93
|
+
- lib/mirrors/visitors/iseq_visitor.rb
|
94
|
+
- lib/mirrors/visitors/references_visitor.rb
|
95
|
+
- lib/mirrors/visitors/yasmdata.rb
|
96
|
+
- lol.rb
|
97
|
+
- mirrors.gemspec
|
98
|
+
- test/fixtures/class.rb
|
99
|
+
- test/fixtures/field.rb
|
100
|
+
- test/fixtures/method.rb
|
101
|
+
- test/fixtures/object.rb
|
102
|
+
- test/fixtures/reflect.rb
|
103
|
+
- test/mirrors/class_mirror_test.rb
|
104
|
+
- test/mirrors/field_mirror_test.rb
|
105
|
+
- test/mirrors/iseq_visitor_test.rb
|
106
|
+
- test/mirrors/marker_test.rb
|
107
|
+
- test/mirrors/method_mirror_test.rb
|
108
|
+
- test/mirrors/object_mirror_test.rb
|
109
|
+
- test/mirrors/package_inference_test.rb
|
110
|
+
- test/mirrors/references_visitor_test.rb
|
111
|
+
- test/mirrors_test.rb
|
112
|
+
- test/test_helper.rb
|
113
|
+
homepage: https://github.com/Shopify/mirrors
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.5.1
|
134
|
+
signing_key:
|
135
|
+
specification_version: 4
|
136
|
+
summary: Mirror API for Ruby
|
137
|
+
test_files: []
|