flutter 0.1.0.pre.2

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 (97) hide show
  1. checksums.yaml +7 -0
  2. data/.overcommit.yml +8 -0
  3. data/.rubocop.yml +10 -0
  4. data/CHANGELOG.md +6 -0
  5. data/CODE_OF_CONDUCT.md +84 -0
  6. data/Gemfile +35 -0
  7. data/Guardfile +9 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +134 -0
  10. data/Rakefile +24 -0
  11. data/TODO.md +30 -0
  12. data/integration_tests/minitest/grape_app/.gitignore +67 -0
  13. data/integration_tests/minitest/grape_app/.ruby-version +1 -0
  14. data/integration_tests/minitest/grape_app/Gemfile +17 -0
  15. data/integration_tests/minitest/grape_app/Gemfile.lock +89 -0
  16. data/integration_tests/minitest/grape_app/README.md +2 -0
  17. data/integration_tests/minitest/grape_app/Rakefile +9 -0
  18. data/integration_tests/minitest/grape_app/api/api.rb +34 -0
  19. data/integration_tests/minitest/grape_app/api/routes/api_helpers.rb +12 -0
  20. data/integration_tests/minitest/grape_app/api/routes/change_request/api.rb +69 -0
  21. data/integration_tests/minitest/grape_app/api/routes/change_request/response_entity.rb +18 -0
  22. data/integration_tests/minitest/grape_app/api/routes/event/api.rb +121 -0
  23. data/integration_tests/minitest/grape_app/api/routes/event/response_entity.rb +41 -0
  24. data/integration_tests/minitest/grape_app/api/routes/project/api.rb +59 -0
  25. data/integration_tests/minitest/grape_app/api/routes/project/response_entity.rb +13 -0
  26. data/integration_tests/minitest/grape_app/api/routes/property/api.rb +78 -0
  27. data/integration_tests/minitest/grape_app/api/routes/property/response_entity.rb +31 -0
  28. data/integration_tests/minitest/grape_app/api/routes/trackable_object/api.rb +64 -0
  29. data/integration_tests/minitest/grape_app/api/routes/trackable_object/response_entity.rb +24 -0
  30. data/integration_tests/minitest/grape_app/api/routes/tracking_spec/api.rb +88 -0
  31. data/integration_tests/minitest/grape_app/api/routes/tracking_spec/response_entity.rb +17 -0
  32. data/integration_tests/minitest/grape_app/api/routes/tracking_spec/spec_response.rb +19 -0
  33. data/integration_tests/minitest/grape_app/api/routes/user/api.rb +22 -0
  34. data/integration_tests/minitest/grape_app/api/routes/user/response_entity.rb +12 -0
  35. data/integration_tests/minitest/grape_app/app/app.rb +30 -0
  36. data/integration_tests/minitest/grape_app/app/change_request/endpoint.rb +24 -0
  37. data/integration_tests/minitest/grape_app/app/change_request/generate_system_changes.rb +25 -0
  38. data/integration_tests/minitest/grape_app/app/change_request/service.rb +79 -0
  39. data/integration_tests/minitest/grape_app/app/event/endpoint.rb +78 -0
  40. data/integration_tests/minitest/grape_app/app/event/service.rb +68 -0
  41. data/integration_tests/minitest/grape_app/app/event/validator.rb +108 -0
  42. data/integration_tests/minitest/grape_app/app/project/endpoint.rb +24 -0
  43. data/integration_tests/minitest/grape_app/app/project/service.rb +42 -0
  44. data/integration_tests/minitest/grape_app/app/property/endpoint.rb +39 -0
  45. data/integration_tests/minitest/grape_app/app/property/service.rb +56 -0
  46. data/integration_tests/minitest/grape_app/app/trackable_object/endpoint.rb +38 -0
  47. data/integration_tests/minitest/grape_app/app/trackable_object/service.rb +49 -0
  48. data/integration_tests/minitest/grape_app/app/trackable_object/validator.rb +40 -0
  49. data/integration_tests/minitest/grape_app/app/tracking_spec/endpoint.rb +58 -0
  50. data/integration_tests/minitest/grape_app/app/tracking_spec/expand_tracking_spec_events.rb +91 -0
  51. data/integration_tests/minitest/grape_app/app/tracking_spec/service.rb +51 -0
  52. data/integration_tests/minitest/grape_app/app/tracking_spec/validator.rb +61 -0
  53. data/integration_tests/minitest/grape_app/app/utils/errors/api_exceptions.rb +10 -0
  54. data/integration_tests/minitest/grape_app/app/utils/errors/service_exceptions.rb +12 -0
  55. data/integration_tests/minitest/grape_app/app/versioned_entity/entity.rb +110 -0
  56. data/integration_tests/minitest/grape_app/app/versioned_entity/service.rb +47 -0
  57. data/integration_tests/minitest/grape_app/app/versioned_entity/validator.rb +61 -0
  58. data/integration_tests/minitest/grape_app/app/versioned_entity_snapshot/entity.rb +32 -0
  59. data/integration_tests/minitest/grape_app/config/boot.rb +9 -0
  60. data/integration_tests/minitest/grape_app/config.ru +3 -0
  61. data/integration_tests/minitest/grape_app/db/proto/change_request.rb +10 -0
  62. data/integration_tests/minitest/grape_app/db/proto/common/doc.rb +86 -0
  63. data/integration_tests/minitest/grape_app/db/proto/event.rb +10 -0
  64. data/integration_tests/minitest/grape_app/db/proto/event_snapshot.rb +10 -0
  65. data/integration_tests/minitest/grape_app/db/proto/project.rb +21 -0
  66. data/integration_tests/minitest/grape_app/db/proto/property.rb +10 -0
  67. data/integration_tests/minitest/grape_app/db/proto/property_snapshot.rb +10 -0
  68. data/integration_tests/minitest/grape_app/db/proto/trackable_object.rb +10 -0
  69. data/integration_tests/minitest/grape_app/db/proto/trackable_object_snapshot.rb +10 -0
  70. data/integration_tests/minitest/grape_app/db/proto/tracking_spec.rb +10 -0
  71. data/integration_tests/minitest/grape_app/test/api/functional/event_test.rb +186 -0
  72. data/integration_tests/minitest/grape_app/test/api/functional/property_test.rb +197 -0
  73. data/integration_tests/minitest/grape_app/test/api/functional/trackable_object_test.rb +134 -0
  74. data/integration_tests/minitest/grape_app/test/api/functional/tracking_spec_test.rb +56 -0
  75. data/integration_tests/minitest/grape_app/test/api/functional/user_test.rb +24 -0
  76. data/integration_tests/minitest/grape_app/test/api/functional/versioned_entity_helper.rb +157 -0
  77. data/integration_tests/minitest/grape_app/test/fixtures/change_requests.rb +83 -0
  78. data/integration_tests/minitest/grape_app/test/fixtures/event_snapshots.rb +105 -0
  79. data/integration_tests/minitest/grape_app/test/fixtures/events.rb +58 -0
  80. data/integration_tests/minitest/grape_app/test/fixtures/properties.rb +66 -0
  81. data/integration_tests/minitest/grape_app/test/fixtures/property_snapshots.rb +124 -0
  82. data/integration_tests/minitest/grape_app/test/fixtures/sample_tracking_spec.json +125 -0
  83. data/integration_tests/minitest/grape_app/test/fixtures/trackable_objects.rb +58 -0
  84. data/integration_tests/minitest/grape_app/test/fixtures/trackable_objects_snapshots.rb +61 -0
  85. data/integration_tests/minitest/grape_app/test/fixtures/tracking_specs.rb +22 -0
  86. data/integration_tests/minitest/grape_app/test/test_helper.rb +15 -0
  87. data/lib/flutter/config.rb +24 -0
  88. data/lib/flutter/minitest.rb +83 -0
  89. data/lib/flutter/parser.rb +82 -0
  90. data/lib/flutter/persistence.rb +152 -0
  91. data/lib/flutter/rspec.rb +66 -0
  92. data/lib/flutter/tracker.rb +133 -0
  93. data/lib/flutter/version.rb +5 -0
  94. data/lib/flutter.rb +12 -0
  95. data/lib/minitest/flutter_plugin.rb +16 -0
  96. data/sig/flutter.rbs +4 -0
  97. metadata +187 -0
@@ -0,0 +1,124 @@
1
+ module Skee
2
+ module Test
3
+ module Fixtures
4
+ class PropertySnapshots
5
+ def self.all
6
+ [
7
+ {
8
+ 'id': '1',
9
+ 'name': 'name',
10
+ 'is_array': false,
11
+ 'property_of': :trackable_object,
12
+ 'data_type': 'String',
13
+ 'description': "user's name",
14
+ 'trackable_object_id': nil,
15
+ 'is_nullable': false,
16
+ 'additional_instructions': nil,
17
+ 'data_format_id': nil,
18
+ 'regex_validation': nil,
19
+ 'change_request_id': '1',
20
+ 'previous_snapshot_id': nil,
21
+ 'is_removed': nil,
22
+ },
23
+ {
24
+ 'id': '2',
25
+ 'name': 'created_at',
26
+ 'is_array': false,
27
+ 'property_of': :event,
28
+ 'data_type': 'String',
29
+ 'description': 'created_at timestamp',
30
+ 'trackable_object_id': nil,
31
+ 'is_nullable': false,
32
+ 'additional_instructions': nil,
33
+ 'data_format_id': nil,
34
+ 'regex_validation': nil,
35
+ 'change_request_id': '1',
36
+ 'previous_snapshot_id': nil,
37
+ 'is_removed': nil,
38
+ },
39
+ {
40
+ 'id': '3',
41
+ 'name': 'products',
42
+ 'is_array': true,
43
+ 'property_of': :trackable_object,
44
+ 'data_type': 'Array',
45
+ 'description': 'list of products',
46
+ 'trackable_object_id': '2',
47
+ 'is_nullable': true,
48
+ 'additional_instructions': nil,
49
+ 'data_format_id': nil,
50
+ 'regex_validation': nil,
51
+ 'change_request_id': '1',
52
+ 'previous_snapshot_id': nil,
53
+ 'is_removed': nil,
54
+ },
55
+ {
56
+ 'id': '4',
57
+ 'name': 'price',
58
+ 'is_array': false,
59
+ 'property_of': :trackable_object,
60
+ 'data_type': 'Float',
61
+ 'description': 'price of products',
62
+ 'trackable_object_id': nil,
63
+ 'is_nullable': true,
64
+ 'additional_instructions': nil,
65
+ 'data_format_id': nil,
66
+ 'regex_validation': nil,
67
+ 'change_request_id': '1',
68
+ 'previous_snapshot_id': nil,
69
+ 'is_removed': nil,
70
+ },
71
+ {
72
+ 'id': '5',
73
+ 'name': 'discount',
74
+ 'is_array': false,
75
+ 'property_of': :trackable_object,
76
+ 'data_type': 'Float',
77
+ 'description': 'discount on products',
78
+ 'trackable_object_id': nil,
79
+ 'is_nullable': true,
80
+ 'additional_instructions': nil,
81
+ 'data_format_id': nil,
82
+ 'regex_validation': nil,
83
+ 'change_request_id': '1',
84
+ 'previous_snapshot_id': '4',
85
+ 'is_removed': nil,
86
+ },
87
+ {
88
+ 'id': '6',
89
+ 'name': 'address',
90
+ 'is_array': false,
91
+ 'property_of': :trackable_object,
92
+ 'data_type': 'String',
93
+ 'description': 'A location address',
94
+ 'trackable_object_id': nil,
95
+ 'is_nullable': true,
96
+ 'additional_instructions': nil,
97
+ 'data_format_id': nil,
98
+ 'regex_validation': nil,
99
+ 'change_request_id': '1',
100
+ 'previous_snapshot_id': '4',
101
+ 'is_removed': nil,
102
+ },
103
+ {
104
+ 'id': '7',
105
+ 'name': 'store_name',
106
+ 'is_array': false,
107
+ 'property_of': :trackable_object,
108
+ 'data_type': 'String',
109
+ 'description': 'Store name',
110
+ 'trackable_object_id': nil,
111
+ 'is_nullable': true,
112
+ 'additional_instructions': nil,
113
+ 'data_format_id': nil,
114
+ 'regex_validation': nil,
115
+ 'change_request_id': '1',
116
+ 'previous_snapshot_id': '4',
117
+ 'is_removed': nil,
118
+ }
119
+ ]
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,125 @@
1
+ [
2
+ {
3
+ "name": "Closed App",
4
+ "description": "Description of event A.",
5
+ "payload": {
6
+ "primary_user": {
7
+ "name": {
8
+ "data_type": "String",
9
+ "description": "user's name",
10
+ "is_nullable": false,
11
+ "additional_instructions": null,
12
+ "data_format_id": null,
13
+ "regex_validation": null,
14
+ "is_removed": null
15
+ }
16
+ },
17
+ "created_timestamp": {
18
+ "data_type": "String",
19
+ "description": "created_at timestamp",
20
+ "is_nullable": false,
21
+ "additional_instructions": null,
22
+ "data_format_id": null,
23
+ "regex_validation": null,
24
+ "is_removed": null
25
+ },
26
+ "cart": {
27
+ "products": [
28
+ {
29
+ "name": {
30
+ "data_type": "String",
31
+ "description": "user's name",
32
+ "is_nullable": false,
33
+ "additional_instructions": null,
34
+ "data_format_id": null,
35
+ "regex_validation": null,
36
+ "is_removed": null
37
+ }
38
+ }
39
+ ]
40
+ }
41
+ }
42
+ },
43
+ {
44
+ "name": "Opened App",
45
+ "description": "Description of event A.",
46
+ "payload": {
47
+ "primary_user": {
48
+ "name": {
49
+ "data_type": "String",
50
+ "description": "user's name",
51
+ "is_nullable": false,
52
+ "additional_instructions": null,
53
+ "data_format_id": null,
54
+ "regex_validation": null,
55
+ "is_removed": null
56
+ }
57
+ },
58
+ "created_timestamp": {
59
+ "data_type": "String",
60
+ "description": "created_at timestamp",
61
+ "is_nullable": false,
62
+ "additional_instructions": null,
63
+ "data_format_id": null,
64
+ "regex_validation": null,
65
+ "is_removed": null
66
+ },
67
+ "cart": {
68
+ "products": [
69
+ {
70
+ "name": {
71
+ "data_type": "String",
72
+ "description": "user's name",
73
+ "is_nullable": false,
74
+ "additional_instructions": null,
75
+ "data_format_id": null,
76
+ "regex_validation": null,
77
+ "is_removed": null
78
+ }
79
+ }
80
+ ]
81
+ }
82
+ }
83
+ },
84
+ {
85
+ "name": "Launched App",
86
+ "description": "Description of event A.",
87
+ "payload": {
88
+ "primary_user": {
89
+ "name": {
90
+ "data_type": "String",
91
+ "description": "user's name",
92
+ "is_nullable": false,
93
+ "additional_instructions": null,
94
+ "data_format_id": null,
95
+ "regex_validation": null,
96
+ "is_removed": null
97
+ }
98
+ },
99
+ "created_timestamp": {
100
+ "data_type": "String",
101
+ "description": "created_at timestamp",
102
+ "is_nullable": false,
103
+ "additional_instructions": null,
104
+ "data_format_id": null,
105
+ "regex_validation": null,
106
+ "is_removed": null
107
+ },
108
+ "cart": {
109
+ "products": [
110
+ {
111
+ "name": {
112
+ "data_type": "String",
113
+ "description": "user's name",
114
+ "is_nullable": false,
115
+ "additional_instructions": null,
116
+ "data_format_id": null,
117
+ "regex_validation": null,
118
+ "is_removed": null
119
+ }
120
+ }
121
+ ]
122
+ }
123
+ }
124
+ }
125
+ ]
@@ -0,0 +1,58 @@
1
+ module Skee
2
+ module Test
3
+ module Fixtures
4
+ class TrackableObjects
5
+ def self.all
6
+ [{
7
+ 'id': '1',
8
+ 'latest_snapshot_id': '1',
9
+ 'snapshot_mapping': {
10
+ '0' => '1'
11
+ },
12
+ 'is_removed': nil,
13
+ }, {
14
+ 'id': '2',
15
+ 'latest_snapshot_id': '2',
16
+ 'snapshot_mapping': {
17
+ '0' => '2'
18
+ },
19
+ 'is_removed': nil,
20
+ }, {
21
+ 'id': '3',
22
+ 'latest_snapshot_id': '3',
23
+ 'snapshot_mapping': {
24
+ '0' => '3'
25
+ },
26
+ 'is_removed': nil,
27
+ }, {
28
+ 'id': '4',
29
+ 'latest_snapshot_id': '4',
30
+ 'snapshot_mapping': {
31
+ },
32
+ 'is_removed': nil,
33
+ }, {
34
+ 'id': '5',
35
+ 'latest_snapshot_id': '4',
36
+ 'snapshot_mapping': {
37
+ },
38
+ 'is_removed': nil,
39
+ }, {
40
+ 'id': '6',
41
+ 'latest_snapshot_id': '6',
42
+ 'snapshot_mapping': {
43
+ '0' => '6'
44
+ },
45
+ 'is_removed': nil,
46
+ }, {
47
+ 'id': '7',
48
+ 'latest_snapshot_id': nil,
49
+ 'snapshot_mapping': {
50
+ },
51
+ 'is_removed': nil,
52
+ }
53
+ ]
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,61 @@
1
+ module Skee
2
+ module Test
3
+ module Fixtures
4
+ class TrackableObjectSnapshots
5
+ def self.all
6
+ [{
7
+ 'id': '1',
8
+ 'name': 'User',
9
+ 'change_request_id': '16',
10
+ 'previous_snapshot_id': nil,
11
+ 'property_ids': ['1'],
12
+ 'is_removed': nil,
13
+ }, {
14
+ 'id': '2',
15
+ 'name': 'Product',
16
+ 'change_request_id': '12',
17
+ 'previous_snapshot_id': nil,
18
+ 'property_ids': ['4'],
19
+ 'is_removed': nil,
20
+ }, {
21
+ 'id': '3',
22
+ 'name': 'Cart',
23
+ 'change_request_id': '16',
24
+ 'previous_snapshot_id': '15',
25
+ 'property_ids': ['3'],
26
+ 'is_removed': nil,
27
+ }, {
28
+ 'id': '4',
29
+ 'name': 'Shop',
30
+ 'change_request_id': '14',
31
+ 'previous_snapshot_id': '15',
32
+ 'property_ids': [],
33
+ 'is_removed': nil,
34
+ }, {
35
+ 'id': '5',
36
+ 'name': 'Shops',
37
+ 'change_request_id': '18',
38
+ 'previous_snapshot_id': '4',
39
+ 'property_ids': [],
40
+ 'is_removed': nil,
41
+ }, {
42
+ 'id': '6',
43
+ 'name': 'Store',
44
+ 'change_request_id': '18',
45
+ 'previous_snapshot_id': nil,
46
+ 'property_ids': ['7', '8'],
47
+ 'is_removed': nil,
48
+ }, {
49
+ 'id': '7',
50
+ 'name': 'Signed-in User',
51
+ 'change_request_id': '1',
52
+ 'previous_snapshot_id': nil,
53
+ 'property_ids': ['1'],
54
+ 'is_removed': nil,
55
+ }
56
+ ]
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,22 @@
1
+ module Skee
2
+ module Test
3
+ module Fixtures
4
+ class TrackingSpecs
5
+ def self.all
6
+ [
7
+ {
8
+ 'id': '1',
9
+ 'identifier': 'Solarbreeze',
10
+ 'version': 'v1',
11
+ 'project_id': '1',
12
+ 'change_request_id': '1',
13
+ 'prev_tracking_spec_id': nil,
14
+ 'status': 'current',
15
+ 'events': ['1', '3', '4'],
16
+ }
17
+ ]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ require 'rack/test'
2
+ require 'minitest/autorun'
3
+ require 'flutter'
4
+ require 'flutter/persistence'
5
+
6
+ require_relative '../config/boot'
7
+
8
+ Flutter.configure do |config|
9
+ config.enabled = true
10
+ end
11
+
12
+
13
+ Dir.glob(File.join(__dir__, 'fixtures/*.rb')).each do |f|
14
+ require_relative f unless File.absolute_path(f) == __FILE__
15
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+ require_relative "persistence"
5
+
6
+ module Flutter
7
+ module Config
8
+ class << self
9
+ private
10
+
11
+ def included(other)
12
+ other.extend(Dry::Configurable)
13
+ other.class_eval do
14
+ setting(:enabled, default: false, reader: true)
15
+ setting(:sources, default: Set.new(["#{Dir.pwd}/*"]))
16
+ setting(:exclusions, default: Set.new(["./vendor/*"]))
17
+ setting(:storage_class, default: Flutter::Persistence::Marshal)
18
+ setting(:storage_options, default: { path: "./.flutter" })
19
+ setting(:reset_storage, default: false)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "tracker"
4
+
5
+ begin
6
+ require "minitest"
7
+ rescue LoadError # rubocop:disable Lint/SuppressedException
8
+ end
9
+
10
+ module Flutter
11
+ module Minitest
12
+ class << self
13
+ attr_accessor :filtered
14
+
15
+ def flutter_tracker
16
+ @tracker ||= Flutter::Tracker.new(
17
+ Flutter.config.sources, Flutter.config.exclusions,
18
+ Flutter.config.storage_class, Flutter.config.storage_options
19
+ )
20
+ end
21
+ end
22
+
23
+ if defined?(::Minitest::AbstractReporter)
24
+ class Reporter < ::Minitest::AbstractReporter
25
+ def initialize(options)
26
+ super()
27
+ @verbose = options[:verbose]
28
+ end
29
+
30
+ def report
31
+ return unless ::Flutter.enabled
32
+
33
+ Flutter::Minitest.flutter_tracker.persist!
34
+ $stdout.puts "Flutter filtered out #{Flutter::Minitest.filtered} tests"
35
+ if @verbose
36
+ $stdout.puts "Persisted flutter #{Flutter::Minitest.flutter_tracker}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ module Hooks
43
+ module ClassMethods
44
+ def runnable_methods
45
+ Flutter::Minitest.filtered ||= 0
46
+ default = super()
47
+ default.select do |test|
48
+ skip = Minitest.flutter_tracker.skip?(
49
+ "#{name}##{test}",
50
+ File.absolute_path(instance_method(test).source_location[0]),
51
+ instance_method(test).source,
52
+ )
53
+ if skip
54
+ Flutter::Minitest.filtered += 1
55
+ end
56
+ !skip
57
+ end
58
+ end
59
+ end
60
+
61
+ def after_setup
62
+ super
63
+ Minitest.flutter_tracker&.start(location) if ::Flutter.enabled
64
+ end
65
+
66
+ def before_teardown
67
+ Minitest.flutter_tracker&.stop if ::Flutter.enabled
68
+ super
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ if defined?(Minitest::Test)
75
+ module Minitest
76
+ class Test
77
+ prepend Flutter::Minitest::Hooks
78
+ class << self
79
+ prepend Flutter::Minitest::Hooks::ClassMethods
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parser/current"
4
+ require "digest/sha1"
5
+ require "set"
6
+
7
+ module Flutter
8
+ class Parser
9
+ attr_reader :signatures
10
+
11
+ def initialize(file)
12
+ @signatures = {}
13
+ @targets = Set.new
14
+ if File.exist?(file)
15
+ code = File.open(file, "r").read
16
+ @file = File.absolute_path(file)
17
+ @ast = ::Parser::CurrentRuby.parse(code)
18
+ collect_targets(nil, nil, false)
19
+ build_signatures
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def collect_targets(ast, parent, in_singleton)
26
+ ast ||= @ast
27
+ if [:module, :class].include?(ast.type)
28
+ @targets << ast.location.name.source unless parent
29
+ parent ||= ast.location.name.source
30
+ end
31
+ ast.children.each do |child|
32
+ if child && (child.class == ::Parser::AST::Node)
33
+ if [:class, :module].include?(child.type)
34
+ child_name = child.location.name.source
35
+ full_name = parent && !child_name.start_with?("::") ? "#{parent}::#{child_name}" : child_name
36
+ @targets << full_name
37
+ collect_targets(child, full_name, false)
38
+ else
39
+ # Don't descend into local scopes as those classes/modules are not relevant
40
+ next if [:def, :defs, :block].include?(child.type)
41
+
42
+ collect_targets(child, parent, in_singleton || child.type == :sclass)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def build_signatures
49
+ require_relative @file
50
+ @targets.each do |container|
51
+ instance = Kernel.const_get(container)
52
+ class_methods = (
53
+ instance.methods - Object.methods
54
+ ) + (
55
+ instance.private_methods - Object.private_methods
56
+ )
57
+ instance_methods = (
58
+ instance.instance_methods - Object.instance_methods
59
+ ) + (
60
+ instance.private_instance_methods - Object.private_instance_methods
61
+ )
62
+
63
+ @signatures.merge!(class_methods.map do |method|
64
+ ["#{container}::#{method}", source_hash(instance.method(method))]
65
+ end.to_h)
66
+ @signatures.merge!(instance_methods.map do |method|
67
+ ["#{container}:#{method}", source_hash(instance.instance_method(method))]
68
+ end.to_h)
69
+ rescue NameError
70
+ $stderr.puts "failed to load #{container} in #{@file}"
71
+ end
72
+ rescue LoadError
73
+ $stderr.puts "failed to inspect #{@file}"
74
+ end
75
+
76
+ def source_hash(callable)
77
+ Digest::SHA1.hexdigest(callable.source)
78
+ rescue MethodSource::SourceNotFoundError
79
+ "<no-source>"
80
+ end
81
+ end
82
+ end