mtrack 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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