modulation 0.15 → 0.16
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +45 -13
- data/lib/modulation/builder.rb +23 -3
- data/lib/modulation/ext.rb +11 -11
- data/lib/modulation/module_mixin.rb +17 -1
- data/lib/modulation/version.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12a1828939d249c28696d296dd5f835e20f2726e101986ca2c9b1168f4fa0ff7
|
4
|
+
data.tar.gz: 53bdc3d0b8cf352030689930b6cf506d144e32d66187ac0a9e4cd564b1a54cfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9edce0c45cbb7885ee1150b85083d2972c54d784c4fc0f74fe020d11e48d916d50eea51efdc2a6250009132186d11071013f14eb15f0e9c1bfaf75d9337a95b5
|
7
|
+
data.tar.gz: 6311006815093c0f15caa25b735710268303a0090bd4fbc45e9e07737d054e40956438eeefaf1431ab62bb636580b42abe7ac908a27a150679f90cbfb4316f8d
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -29,6 +29,7 @@ code in a functional style, with a minimum of boilerplate code.
|
|
29
29
|
code in wierd ways.
|
30
30
|
- Allows [mocking of dependencies](#mocking-dependencies) for testing purposes.
|
31
31
|
- Can be used to [write gems](#writing-gems-using-modulation).
|
32
|
+
- Facilitates [unit-testing](#unit-testing-modules) of private methods and constants.
|
32
33
|
|
33
34
|
## Rationale
|
34
35
|
|
@@ -266,6 +267,40 @@ end
|
|
266
267
|
what = ::MEANING_OF_LIFE
|
267
268
|
```
|
268
269
|
|
270
|
+
### Unit testing modules
|
271
|
+
|
272
|
+
Methods and constants that are not exported can be tested using the `__expose!`
|
273
|
+
method. Thus you can keep implementation details hidden, while being able to
|
274
|
+
easily test them:
|
275
|
+
|
276
|
+
*parser.rb*
|
277
|
+
```ruby
|
278
|
+
export :parse
|
279
|
+
|
280
|
+
def parse(inp)
|
281
|
+
split(inp).map(&:to_sym)
|
282
|
+
end
|
283
|
+
|
284
|
+
# private method
|
285
|
+
def split(inp)
|
286
|
+
inp.split(',').map(&:strip)
|
287
|
+
end
|
288
|
+
```
|
289
|
+
|
290
|
+
*test_seq.rb*
|
291
|
+
```ruby
|
292
|
+
require 'modulation'
|
293
|
+
require 'minitest/autorun'
|
294
|
+
|
295
|
+
Parser = import('../lib/parser').__expose!
|
296
|
+
|
297
|
+
class FibTest < Minitest::Test
|
298
|
+
def test_that_split_trims_split_parts
|
299
|
+
assert_equal(%w[abc def ghi], Parser.split(' abc ,def , ghi '))
|
300
|
+
end
|
301
|
+
end
|
302
|
+
```
|
303
|
+
|
269
304
|
### Mocking dependencies
|
270
305
|
|
271
306
|
Modules loaded by Modulation can be easily mocked when running tests or specs,
|
@@ -290,8 +325,8 @@ end
|
|
290
325
|
class UserControllerTest < Minitest::Test
|
291
326
|
def test_user_storage
|
292
327
|
Modulation.mock('../lib/storage', MockStorage) do
|
293
|
-
controller = UserController.
|
294
|
-
|
328
|
+
controller = UserController.new
|
329
|
+
...
|
295
330
|
end
|
296
331
|
end
|
297
332
|
end
|
@@ -370,32 +405,29 @@ MyFeature = import 'my_gem/my_feature'
|
|
370
405
|
|
371
406
|
## Coding style recommendations
|
372
407
|
|
373
|
-
* Import modules into constants, not
|
408
|
+
* Import modules into constants, not variables:
|
374
409
|
|
375
410
|
```ruby
|
376
411
|
Settings = import('./settings')
|
377
412
|
```
|
378
413
|
|
379
|
-
* Place your exports at the top of your module
|
414
|
+
* Place your exports at the top of your module, followed by `require`s,
|
415
|
+
followed by `import`s:
|
380
416
|
|
381
417
|
```ruby
|
382
418
|
export :foo, :bar, :baz
|
383
419
|
|
384
|
-
|
385
|
-
```
|
386
|
-
|
387
|
-
* Place your imports at the top of your module:
|
420
|
+
require 'json'
|
388
421
|
|
389
|
-
|
390
|
-
|
391
|
-
Bar = import('./bar')
|
392
|
-
Baz = import('./baz')
|
422
|
+
Core = import('./core')
|
423
|
+
|
393
424
|
...
|
394
425
|
```
|
395
426
|
|
427
|
+
|
396
428
|
## Why you should not use Modulation
|
397
429
|
|
398
|
-
- Modulation is
|
430
|
+
- Modulation is not production-ready.
|
399
431
|
- Modulation is not thread-safe.
|
400
432
|
- Modulation doesn't play well with rdoc/yard.
|
401
433
|
- Modulation (probably) doesn't play well with `Marshal`.
|
data/lib/modulation/builder.rb
CHANGED
@@ -52,15 +52,35 @@ module Modulation
|
|
52
52
|
def set_exported_symbols(mod, symbols)
|
53
53
|
mod.__module_info[:exported_symbols] = symbols
|
54
54
|
singleton = mod.singleton_class
|
55
|
+
|
56
|
+
privatize_non_exported_methods(singleton, symbols)
|
57
|
+
expose_exported_constants(mod, singleton, symbols)
|
58
|
+
end
|
55
59
|
|
60
|
+
# Sets all non-exported methods as private for given module
|
61
|
+
# @param singleton [Class] sinleton for module
|
62
|
+
# @param symbols [Array] array of exported symbols
|
63
|
+
# @return [void]
|
64
|
+
def privatize_non_exported_methods(singleton, symbols)
|
56
65
|
singleton.instance_methods(false).each do |sym|
|
57
66
|
next if symbols.include?(sym)
|
58
67
|
singleton.send(:private, sym)
|
59
68
|
end
|
69
|
+
end
|
60
70
|
|
61
|
-
|
62
|
-
|
63
|
-
|
71
|
+
# Copies exported constants from singleton to module
|
72
|
+
# @param mod [Module] module with exported symbols
|
73
|
+
# @param singleton [Class] sinleton for module
|
74
|
+
# @param symbols [Array] array of exported symbols
|
75
|
+
# @return [void]
|
76
|
+
def expose_exported_constants(mod, singleton, symbols)
|
77
|
+
private_constants = mod.__module_info[:private_constants] = []
|
78
|
+
singleton.constants(false).each do |sym|
|
79
|
+
if symbols.include?(sym)
|
80
|
+
mod.const_set(sym, singleton.const_get(sym))
|
81
|
+
else
|
82
|
+
private_constants << sym unless sym == :MODULE
|
83
|
+
end
|
64
84
|
end
|
65
85
|
end
|
66
86
|
|
data/lib/modulation/ext.rb
CHANGED
@@ -18,14 +18,8 @@ class Module
|
|
18
18
|
# @return [void]
|
19
19
|
def extend_from(path)
|
20
20
|
mod = import(path, caller(1..1).first)
|
21
|
-
mod.
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
mod.singleton_class.constants(false).each do |sym|
|
26
|
-
next if sym == :MODULE
|
27
|
-
const_set(sym, mod.singleton_class.const_get(sym))
|
28
|
-
end
|
21
|
+
add_module_methods(mod, self.class)
|
22
|
+
add_module_constants(mod, self)
|
29
23
|
end
|
30
24
|
|
31
25
|
# Includes exported methods from the given file name in the receiver
|
@@ -34,15 +28,21 @@ class Module
|
|
34
28
|
# @return [void]
|
35
29
|
def include_from(path)
|
36
30
|
mod = import(path, caller(1..1).first)
|
37
|
-
|
31
|
+
add_module_methods(mod, self)
|
32
|
+
add_module_constants(mod, self)
|
33
|
+
end
|
38
34
|
|
35
|
+
def add_module_methods(mod, target)
|
39
36
|
mod.singleton_class.instance_methods(false).each do |sym|
|
40
|
-
send(:define_method, sym, &mod.method(sym))
|
37
|
+
target.send(:define_method, sym, &mod.method(sym))
|
41
38
|
end
|
39
|
+
end
|
42
40
|
|
41
|
+
def add_module_constants(mod, target)
|
42
|
+
exported_symbols = mod.__module_info[:exported_symbols]
|
43
43
|
mod.singleton_class.constants(false).each do |sym|
|
44
44
|
next unless exported_symbols.include?(sym)
|
45
|
-
const_set(sym, mod.singleton_class.const_get(sym))
|
45
|
+
target.const_set(sym, mod.singleton_class.const_get(sym))
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -76,8 +76,24 @@ module Modulation
|
|
76
76
|
|
77
77
|
# Allow modules to use attr_accessor/reader/writer and include methods by
|
78
78
|
# forwarding calls to singleton_class
|
79
|
-
[
|
79
|
+
%i[attr_accessor attr_reader attr_writer include].each do |sym|
|
80
80
|
define_method(sym) { |*args| singleton_class.send(sym, *args) }
|
81
81
|
end
|
82
|
+
|
83
|
+
# Exposes all private methods and private constants as public
|
84
|
+
# @return [Module] self
|
85
|
+
def __expose!
|
86
|
+
singleton = singleton_class
|
87
|
+
|
88
|
+
singleton.private_instance_methods.each do |sym|
|
89
|
+
singleton.send(:public, sym)
|
90
|
+
end
|
91
|
+
|
92
|
+
__module_info[:private_constants].each do |sym|
|
93
|
+
const_set(sym, singleton.const_get(sym))
|
94
|
+
end
|
95
|
+
|
96
|
+
self
|
97
|
+
end
|
82
98
|
end
|
83
99
|
end
|
data/lib/modulation/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: modulation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.16'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|