mtrack 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.
@@ -0,0 +1,55 @@
1
+ require "set"
2
+
3
+ module MTrack
4
+ class State
5
+
6
+ ##
7
+ # Handles method information for each group in MTrack::State#groups.
8
+ class Group
9
+
10
+ ##
11
+ # call-seq:
12
+ # new() => new_group
13
+ #
14
+ # Creates a new Group instance.
15
+ def initialize
16
+ self.tracked = Set.new
17
+ end
18
+
19
+ ##
20
+ # call-seq:
21
+ # delete_tracked(name) => name
22
+ #
23
+ # Removes method +name+ from tracked methods.
24
+ def delete_tracked(name)
25
+ @tracked.delete name
26
+ name
27
+ end
28
+
29
+ ##
30
+ # call-seq:
31
+ # merge_tracked(names) => names
32
+ #
33
+ # Adds method +names+ to tracked methods.
34
+ def merge_tracked(names)
35
+ @tracked.merge names
36
+ names
37
+ end
38
+
39
+ ##
40
+ # call-seq:
41
+ # tracked() => new_set
42
+ #
43
+ # Returns a new set containing the methods currently being tracked.
44
+ def tracked
45
+ @tracked.dup
46
+ end
47
+
48
+ private
49
+
50
+ ##
51
+ # A set containing the method names currently being tracked.
52
+ attr_writer :tracked
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ ##
2
+ # MTrack extends the functionality of Modules and Classes and enables them to
3
+ # define public methods within groups. These methods can then be queried back
4
+ # even through a hierarchy of inclusion and/or inheritance.
5
+ #
6
+ # module M
7
+ # track_methods { def method_1; end }
8
+ # end
9
+ #
10
+ # class C
11
+ # include M
12
+ # track_methods { def method_2; end }
13
+ # end
14
+ #
15
+ # class D < C
16
+ # track_methods { def method_3; end }
17
+ # end
18
+ #
19
+ # D.tracked_methods #=> #<Set: {:method_1, :method_2, :method_3}>
20
+ module MTrack
21
+
22
+ # Current version of MTrack.
23
+ VERSION = "0.0.1"
24
+ end
data/mtrack.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "mtrack/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mtrack"
8
+ spec.version = MTrack::VERSION
9
+ spec.authors = ["Gabriel de Oliveira"]
10
+ spec.email = ["deoliveira.gab@gmail.com"]
11
+ spec.summary = %q{Group and track methods on classes and modules.}
12
+ spec.description = <<-EOS.strip.gsub(/\n/, "").gsub(/\s{2,}/, " ")
13
+ MTrack extends the functionality of modules and
14
+ classes and enables them to define public methods
15
+ within groups. These methods can then be queried back
16
+ even through a hierarchy of inclusion and/or
17
+ inheritance.
18
+ EOS
19
+ spec.homepage = "https://github.com/gdeoliveira/mtrack"
20
+ spec.license = "MIT"
21
+
22
+ spec.files = `git ls-files -z`.split("\x0")
23
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_development_dependency "bundler"
27
+ spec.add_development_dependency "codeclimate-test-reporter"
28
+ spec.add_development_dependency "pry"
29
+ spec.add_development_dependency "rake"
30
+ spec.add_development_dependency "rspec"
31
+ spec.add_development_dependency "simplecov"
32
+ end
@@ -0,0 +1,377 @@
1
+ require "spec_helper"
2
+
3
+ METHOD_DEFINITION = proc {}
4
+
5
+ describe MTrack::Core do
6
+ let(:base_module_1) do
7
+ Module.new.tap do |m|
8
+ m.module_eval do
9
+ define_method :unt_1, METHOD_DEFINITION
10
+ track_methods { define_method :meth, METHOD_DEFINITION }
11
+ track_methods :numbers do
12
+ track_methods(:odd) { define_method :one, METHOD_DEFINITION }
13
+ track_methods(:even) { define_method :two, METHOD_DEFINITION }
14
+ end
15
+ define_method :unt_2, METHOD_DEFINITION
16
+ end
17
+ end
18
+ end
19
+
20
+ let(:base_module_2) do
21
+ Module.new.tap do |m|
22
+ m.module_eval do
23
+ define_method :unt_2, METHOD_DEFINITION
24
+ track_methods { define_method :meth, METHOD_DEFINITION }
25
+ track_methods :numbers do
26
+ track_methods(:even) { define_method :two, METHOD_DEFINITION }
27
+ track_methods(:odd) { define_method :three, METHOD_DEFINITION }
28
+ end
29
+ define_method :unt_3, METHOD_DEFINITION
30
+ end
31
+ end
32
+ end
33
+
34
+ let(:base_module_3) do
35
+ Module.new.tap do |m|
36
+ m.module_eval do
37
+ define_method :unt_3, METHOD_DEFINITION
38
+ track_methods { define_method :meth, METHOD_DEFINITION }
39
+ track_methods :numbers do
40
+ track_methods(:odd) { define_method :three, METHOD_DEFINITION }
41
+ track_methods(:even) { define_method :four, METHOD_DEFINITION }
42
+ end
43
+ define_method :unt_4, METHOD_DEFINITION
44
+ end
45
+ end
46
+ end
47
+
48
+ let(:sub_module_1) do
49
+ bm_1 = base_module_1
50
+ bm_2 = base_module_2
51
+ Module.new.tap do |m|
52
+ m.module_eval do
53
+ include bm_1
54
+ define_method :unt_4, METHOD_DEFINITION
55
+ track_methods { define_method :meth, METHOD_DEFINITION }
56
+ track_methods :numbers do
57
+ track_methods(:even) { define_method :four, METHOD_DEFINITION }
58
+ track_methods(:odd) { define_method :five, METHOD_DEFINITION }
59
+ end
60
+ define_method :unt_5, METHOD_DEFINITION
61
+ include bm_2
62
+ end
63
+ end
64
+ end
65
+
66
+ let(:sub_module_2) do
67
+ bm_3 = base_module_3
68
+ Module.new.tap do |m|
69
+ m.module_eval do
70
+ define_method :unt_5, METHOD_DEFINITION
71
+ track_methods { define_method :meth, METHOD_DEFINITION }
72
+ include bm_3
73
+ track_methods :numbers do
74
+ track_methods(:odd) { define_method :five, METHOD_DEFINITION }
75
+ track_methods(:even) { define_method :six, METHOD_DEFINITION }
76
+ end
77
+ define_method :unt_6, METHOD_DEFINITION
78
+ end
79
+ end
80
+ end
81
+
82
+ let(:super_class) do
83
+ sm_1 = sub_module_1
84
+ Class.new.tap do |c|
85
+ c.class_eval do
86
+ include sm_1
87
+ define_method :unt_6, METHOD_DEFINITION
88
+ track_methods { define_method :meth, METHOD_DEFINITION }
89
+ track_methods :numbers do
90
+ track_methods(:even) { define_method :six, METHOD_DEFINITION }
91
+ track_methods(:odd) { define_method :seven, METHOD_DEFINITION }
92
+ end
93
+ define_method :unt_7, METHOD_DEFINITION
94
+ end
95
+ end
96
+ end
97
+
98
+ let(:sub_class) do
99
+ sm_2 = sub_module_2
100
+ sc = super_class
101
+ Class.new(sc).tap do |c|
102
+ c.class_eval do
103
+ define_method :unt_7, METHOD_DEFINITION
104
+ track_methods { define_method :meth, METHOD_DEFINITION }
105
+ track_methods :numbers do
106
+ track_methods(:odd) { define_method :seven, METHOD_DEFINITION }
107
+ track_methods(:even) { define_method :eight, METHOD_DEFINITION }
108
+ end
109
+ define_method :unt_8, METHOD_DEFINITION
110
+ include sm_2
111
+ end
112
+ end
113
+ end
114
+
115
+ context "base module 1" do
116
+ subject { base_module_1 }
117
+
118
+ it "tracks methods" do
119
+ expect(subject.tracked_methods).to match_array([:meth])
120
+ expect(subject.tracked_methods(:numbers)).to match_array([:one, :two])
121
+ expect(subject.tracked_methods(:odd)).to match_array([:one])
122
+ expect(subject.tracked_methods(:even)).to match_array([:two])
123
+ end
124
+
125
+ it "untracks removed methods" do
126
+ subject.module_eval { remove_method :meth }
127
+ expect(subject.tracked_methods).to be_empty
128
+ end
129
+
130
+ it "untracks undefined methods" do
131
+ subject.module_eval { undef_method :meth }
132
+ expect(subject.tracked_methods).to be_empty
133
+
134
+ subject.module_eval { define_method :meth, METHOD_DEFINITION }
135
+ expect(subject.tracked_methods).to be_empty
136
+ end
137
+ end
138
+
139
+ context "base module 2" do
140
+ subject { base_module_2 }
141
+
142
+ it "tracks methods" do
143
+ expect(subject.tracked_methods).to match_array([:meth])
144
+ expect(subject.tracked_methods(:numbers)).to match_array([:two, :three])
145
+ expect(subject.tracked_methods(:even)).to match_array([:two])
146
+ expect(subject.tracked_methods(:odd)).to match_array([:three])
147
+ end
148
+
149
+ it "untracks removed methods" do
150
+ subject.module_eval { remove_method :meth }
151
+ expect(subject.tracked_methods).to be_empty
152
+ end
153
+
154
+ it "untracks undefined methods" do
155
+ subject.module_eval { undef_method :meth }
156
+ expect(subject.tracked_methods).to be_empty
157
+
158
+ subject.module_eval { define_method :meth, METHOD_DEFINITION }
159
+ expect(subject.tracked_methods).to be_empty
160
+ end
161
+ end
162
+
163
+ context "base module 3" do
164
+ subject { base_module_3 }
165
+
166
+ it "tracks methods" do
167
+ expect(subject.tracked_methods).to match_array([:meth])
168
+ expect(subject.tracked_methods(:numbers)).to match_array([:three, :four])
169
+ expect(subject.tracked_methods(:odd)).to match_array([:three])
170
+ expect(subject.tracked_methods(:even)).to match_array([:four])
171
+ end
172
+
173
+ it "untracks removed methods" do
174
+ subject.module_eval { remove_method :meth }
175
+ expect(subject.tracked_methods).to be_empty
176
+ end
177
+
178
+ it "untracks undefined methods" do
179
+ subject.module_eval { undef_method :meth }
180
+ expect(subject.tracked_methods).to be_empty
181
+
182
+ subject.module_eval { define_method :meth, METHOD_DEFINITION }
183
+ expect(subject.tracked_methods).to be_empty
184
+ end
185
+ end
186
+
187
+ context "sub module 1" do
188
+ subject { sub_module_1 }
189
+
190
+ it "tracks methods" do
191
+ expect(subject.tracked_methods).to match_array([:meth])
192
+ expect(subject.tracked_methods(:numbers)).to match_array([:one, :two, :three, :four, :five])
193
+ expect(subject.tracked_methods(:odd)).to match_array([:one, :three, :five])
194
+ expect(subject.tracked_methods(:even)).to match_array([:two, :four])
195
+ end
196
+
197
+ it "untracks removed methods" do
198
+ subject.module_eval { remove_method :meth }
199
+ expect(subject.tracked_methods).to match_array([:meth])
200
+
201
+ base_module_1.module_eval { remove_method :meth }
202
+ expect(subject.tracked_methods).to match_array([:meth])
203
+
204
+ base_module_2.module_eval { remove_method :meth }
205
+ expect(subject.tracked_methods).to be_empty
206
+ end
207
+
208
+ it "untracks undefined methods" do
209
+ subject.module_eval { undef_method :meth }
210
+ expect(subject.tracked_methods).to be_empty
211
+
212
+ subject.module_eval { define_method :meth, METHOD_DEFINITION }
213
+ expect(subject.tracked_methods).to match_array([:meth])
214
+ end
215
+ end
216
+
217
+ context "sub module 2" do
218
+ subject { sub_module_2 }
219
+
220
+ it "tracks methods" do
221
+ expect(subject.tracked_methods).to match_array([:meth])
222
+ expect(subject.tracked_methods(:numbers)).to match_array([:three, :four, :five, :six])
223
+ expect(subject.tracked_methods(:odd)).to match_array([:three, :five])
224
+ expect(subject.tracked_methods(:even)).to match_array([:four, :six])
225
+ end
226
+
227
+ it "untracks removed methods" do
228
+ base_module_3.module_eval { remove_method :meth }
229
+ expect(subject.tracked_methods).to match_array([:meth])
230
+
231
+ subject.module_eval { remove_method :meth }
232
+ expect(subject.tracked_methods).to be_empty
233
+ end
234
+
235
+ it "untracks undefined methods" do
236
+ subject.module_eval { undef_method :meth }
237
+ expect(subject.tracked_methods).to be_empty
238
+
239
+ subject.module_eval { define_method :meth, METHOD_DEFINITION }
240
+ expect(subject.tracked_methods).to match_array([:meth])
241
+ end
242
+ end
243
+
244
+ context "super class" do
245
+ subject { super_class }
246
+
247
+ it "tracks methods" do
248
+ expect(subject.tracked_methods).to match_array([:meth])
249
+ expect(subject.tracked_methods(:numbers)).to match_array([:one, :two, :three, :four, :five, :six, :seven])
250
+ expect(subject.tracked_methods(:odd)).to match_array([:one, :three, :five, :seven])
251
+ expect(subject.tracked_methods(:even)).to match_array([:two, :four, :six])
252
+ end
253
+
254
+ it "untracks removed methods" do
255
+ subject.class_eval { remove_method :meth }
256
+ expect(subject.tracked_methods).to match_array([:meth])
257
+
258
+ sub_module_1.module_eval { remove_method :meth }
259
+ expect(subject.tracked_methods).to match_array([:meth])
260
+
261
+ base_module_2.module_eval { remove_method :meth }
262
+ expect(subject.tracked_methods).to match_array([:meth])
263
+
264
+ base_module_1.module_eval { remove_method :meth }
265
+ expect(subject.tracked_methods).to be_empty
266
+ end
267
+
268
+ it "untracks undefined methods" do
269
+ subject.module_eval { undef_method :meth }
270
+ expect(subject.tracked_methods).to be_empty
271
+
272
+ subject.module_eval { define_method :meth, METHOD_DEFINITION }
273
+ expect(subject.tracked_methods).to match_array([:meth])
274
+ end
275
+ end
276
+
277
+ context "sub class" do
278
+ subject { sub_class }
279
+
280
+ it "tracks methods" do
281
+ expect(subject.tracked_methods).to match_array([:meth])
282
+ expect(subject.tracked_methods(:numbers)).to match_array([:one, :two, :three, :four, :five, :six, :seven, :eight])
283
+ expect(subject.tracked_methods(:odd)).to match_array([:one, :three, :five, :seven])
284
+ expect(subject.tracked_methods(:even)).to match_array([:two, :four, :six, :eight])
285
+ end
286
+
287
+ it "untracks removed methods" do
288
+ base_module_1.module_eval { remove_method :meth }
289
+ expect(subject.tracked_methods).to match_array([:meth])
290
+
291
+ base_module_2.module_eval { remove_method :meth }
292
+ expect(subject.tracked_methods).to match_array([:meth])
293
+
294
+ base_module_3.module_eval { remove_method :meth }
295
+ expect(subject.tracked_methods).to match_array([:meth])
296
+
297
+ sub_module_1.module_eval { remove_method :meth }
298
+ expect(subject.tracked_methods).to match_array([:meth])
299
+
300
+ sub_module_2.module_eval { remove_method :meth }
301
+ expect(subject.tracked_methods).to match_array([:meth])
302
+
303
+ super_class.class_eval { remove_method :meth }
304
+ expect(subject.tracked_methods).to match_array([:meth])
305
+
306
+ subject.class_eval { remove_method :meth }
307
+ expect(subject.tracked_methods).to be_empty
308
+ end
309
+
310
+ it "untracks undefined methods" do
311
+ subject.module_eval { undef_method :meth }
312
+ expect(subject.tracked_methods).to be_empty
313
+
314
+ subject.module_eval { define_method :meth, METHOD_DEFINITION }
315
+ expect(subject.tracked_methods).to match_array([:meth])
316
+ end
317
+ end
318
+
319
+ context "partially defined" do
320
+ context "module" do
321
+ it "tracks methods" do
322
+ m = ::Module.new
323
+
324
+ expect do
325
+ m.module_eval do
326
+ track_methods do
327
+ define_method :meth_1, METHOD_DEFINITION
328
+ define_method :meth_2, METHOD_DEFINITION
329
+ raise "Unexpected error"
330
+ define_method :meth_3, METHOD_DEFINITION
331
+ define_method :meth_4, METHOD_DEFINITION
332
+ end
333
+ end
334
+ end.to raise_error(RuntimeError, "Unexpected error")
335
+
336
+ expect(m.public_instance_methods(false).map(&:to_sym)).to match_array([:meth_1, :meth_2])
337
+ expect(m.tracked_methods).to match_array([:meth_1, :meth_2])
338
+ end
339
+ end
340
+
341
+ context "class" do
342
+ it "tracks methods" do
343
+ c = ::Class.new
344
+
345
+ expect do
346
+ c.class_eval do
347
+ track_methods do
348
+ define_method :meth_1, METHOD_DEFINITION
349
+ define_method :meth_2, METHOD_DEFINITION
350
+ raise "Unexpected error"
351
+ define_method :meth_3, METHOD_DEFINITION
352
+ define_method :meth_4, METHOD_DEFINITION
353
+ end
354
+ end
355
+ end.to raise_error(RuntimeError, "Unexpected error")
356
+
357
+ expect(c.public_instance_methods(false).map(&:to_sym)).to match_array([:meth_1, :meth_2])
358
+ expect(c.tracked_methods).to match_array([:meth_1, :meth_2])
359
+ end
360
+ end
361
+ end
362
+
363
+ context "inclusion" do
364
+ it "adds #{described_class} to submodule" do
365
+ bm_1 = base_module_1
366
+ m = ::Module.new.module_eval { include bm_1 }
367
+ expect(m.tracked_methods).to match_array([:meth])
368
+ end
369
+ end
370
+
371
+ context "inheritance" do
372
+ it "adds #{described_class} to subclass" do
373
+ c = ::Class.new(super_class)
374
+ expect(c.tracked_methods).to match_array([:meth])
375
+ end
376
+ end
377
+ end