mirrors 0.0.1

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.
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: []