mirrors 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rubocop.yml +2 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +23 -0
  6. data/LICENSE.txt +59 -0
  7. data/README.md +1 -0
  8. data/asdfasdf.rb +53 -0
  9. data/bin/bundler +17 -0
  10. data/bin/byebug +17 -0
  11. data/bin/testunit +8 -0
  12. data/circle.yml +6 -0
  13. data/dev.yml +6 -0
  14. data/lib/mirrors.rb +150 -0
  15. data/lib/mirrors/class_mirror.rb +197 -0
  16. data/lib/mirrors/class_mixin.rb +11 -0
  17. data/lib/mirrors/field_mirror.rb +24 -0
  18. data/lib/mirrors/field_mirror/class_variable_mirror.rb +23 -0
  19. data/lib/mirrors/field_mirror/constant_mirror.rb +34 -0
  20. data/lib/mirrors/field_mirror/instance_variable_mirror.rb +23 -0
  21. data/lib/mirrors/hook.rb +33 -0
  22. data/lib/mirrors/index/indexer.rb +6 -0
  23. data/lib/mirrors/index/marker.rb +40 -0
  24. data/lib/mirrors/invoke.rb +29 -0
  25. data/lib/mirrors/method_mirror.rb +206 -0
  26. data/lib/mirrors/mirror.rb +37 -0
  27. data/lib/mirrors/object_mirror.rb +25 -0
  28. data/lib/mirrors/package_inference.rb +164 -0
  29. data/lib/mirrors/package_inference/class_to_file_resolver.rb +66 -0
  30. data/lib/mirrors/package_mirror.rb +33 -0
  31. data/lib/mirrors/visitors/disasm_visitor.rb +11 -0
  32. data/lib/mirrors/visitors/iseq_visitor.rb +84 -0
  33. data/lib/mirrors/visitors/references_visitor.rb +58 -0
  34. data/lib/mirrors/visitors/yasmdata.rb +212 -0
  35. data/lol.rb +35 -0
  36. data/mirrors.gemspec +19 -0
  37. data/test/fixtures/class.rb +29 -0
  38. data/test/fixtures/field.rb +9 -0
  39. data/test/fixtures/method.rb +15 -0
  40. data/test/fixtures/object.rb +5 -0
  41. data/test/fixtures/reflect.rb +14 -0
  42. data/test/mirrors/class_mirror_test.rb +87 -0
  43. data/test/mirrors/field_mirror_test.rb +125 -0
  44. data/test/mirrors/iseq_visitor_test.rb +56 -0
  45. data/test/mirrors/marker_test.rb +48 -0
  46. data/test/mirrors/method_mirror_test.rb +62 -0
  47. data/test/mirrors/object_mirror_test.rb +16 -0
  48. data/test/mirrors/package_inference_test.rb +31 -0
  49. data/test/mirrors/references_visitor_test.rb +30 -0
  50. data/test/mirrors_test.rb +38 -0
  51. data/test/test_helper.rb +12 -0
  52. 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
@@ -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: []