modulation 0.16 → 0.17
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 +57 -52
- data/lib/modulation/version.rb +1 -1
- 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: 5daf7340b5dc5c4e5efb09a751b1e1fe6bd65fc79a76182bf665174b3287e95c
|
4
|
+
data.tar.gz: 6840631ce8268a819d47796b61d4b74dbabed5f5ad6e368c55705fdce40997aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f89f42981f3418d165af0c978291259b21ffc2480f0dd4506f1701daa23fbde3f355950962ad081479e9d1ebc9dd68e11f02a23c644d90c8200cece2d372e80
|
7
|
+
data.tar.gz: 760c2cfbfb460712f122782b57edbef1cb12ab030dbf82b5399ccc6c84a20056d70ecb8ce9eaae4b820d33305e60908b55df61ecbad24033e0f0e01d14214c6c
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,20 +1,26 @@
|
|
1
|
-
# Modulation -
|
1
|
+
# Modulation - Explicit Dependency Management for Ruby
|
2
2
|
|
3
3
|
[INSTALL](#installing-modulation) |
|
4
4
|
[GUIDE](#organizing-your-code-with-modulation) |
|
5
|
-
[EXAMPLES](
|
6
|
-
[
|
5
|
+
[EXAMPLES](examples) |
|
6
|
+
[RDOC](https://www.rubydoc.info/gems/modulation/)
|
7
7
|
|
8
|
-
Modulation provides an
|
9
|
-
explicitly import and export declarations in order to better control
|
8
|
+
Modulation provides an alternative way of organizing your Ruby code. Modulation
|
9
|
+
lets you explicitly import and export declarations in order to better control
|
10
10
|
dependencies in your codebase. Modulation helps you refrain from littering
|
11
|
-
the global namespace with a myriad modules, or
|
12
|
-
|
11
|
+
the global namespace with a myriad modules, or complex multi-level nested
|
12
|
+
module hierarchies.
|
13
13
|
|
14
|
-
Using Modulation, you will always be able to tell
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
Using Modulation, you will always be able to tell where a class or module comes
|
15
|
+
from, and you'll have full control over which parts of a module's code you wish
|
16
|
+
to expose to the outside world. Modulation can also help you write Ruby code in
|
17
|
+
a functional style, minimizing boilerplate code.
|
18
|
+
|
19
|
+
> Note: Modulation is not a replacement for RubyGems. Rather, Modulation is
|
20
|
+
> intended for managing dependencies between source files *inside* your Ruby
|
21
|
+
> applications. Though it does support loading gems that were written using
|
22
|
+
> Modulation, it is not intended as a comprehensive solution for using
|
23
|
+
> third-party libraries.
|
18
24
|
|
19
25
|
## Features
|
20
26
|
|
@@ -33,8 +39,9 @@ code in a functional style, with a minimum of boilerplate code.
|
|
33
39
|
|
34
40
|
## Rationale
|
35
41
|
|
36
|
-
You're probably asking yourself "what the
|
37
|
-
into multiple files loaded using `require
|
42
|
+
You're probably asking yourself "what the ****?" , but when your Ruby app grows
|
43
|
+
and is split into multiple files loaded using `require`, you'll soon hit some
|
44
|
+
issues:
|
38
45
|
|
39
46
|
- Once a file is `require`d, any class, module or constant in it is available
|
40
47
|
to any other file in your codebase. All "globals" (classes, modules,
|
@@ -45,37 +52,30 @@ into multiple files loaded using `require` poses a number of problems:
|
|
45
52
|
- Since a `require`d class or module can be loaded in any file and then made
|
46
53
|
available to all files, it's easy to lose track of where it was loaded, and
|
47
54
|
where it is used.
|
48
|
-
- There's no easy way to
|
49
|
-
|
55
|
+
- There's no easy way to hide implementation-specific classes or methods. Yes,
|
56
|
+
there's `private`, `private_constant` etc, but by default everything is
|
57
|
+
`public`!
|
50
58
|
- Writing reusable functional code requires wrapping it in modules using
|
51
|
-
`class << self`, `def self.foo ...`, `extend self` or `include Singleton
|
59
|
+
`class << self`, `def self.foo ...`, `extend self` or `include Singleton`
|
60
|
+
(the pain of implementing singletons in Ruby has been
|
61
|
+
[discussed](https://practicingruby.com/articles/ruby-and-the-singleton-pattern-dont-get-along)
|
62
|
+
[before](https://ieftimov.com/singleton-pattern).)
|
63
|
+
|
64
|
+
> There's a [recent discussion](https://bugs.ruby-lang.org/issues/14982) on the
|
65
|
+
> Ruby bug tracker regarding possible solutions to the problem of top-level
|
66
|
+
> name collision. Hopefully, the present gem could contribute to an eventual
|
67
|
+
> "official" API.
|
52
68
|
|
53
69
|
Personally, I have found that managing dependencies with `require` in large
|
54
70
|
codebases is... not as elegant or painfree as I would expect from a
|
55
71
|
first-class development environment. I also wanted to have a better solution
|
56
72
|
for writing in a functional style.
|
57
73
|
|
58
|
-
So I came up with Modulation, a small gem that takes a
|
59
|
-
organizing Ruby code: any so-called global declarations
|
60
|
-
explicitly exported, and the global namespace remains
|
61
|
-
dependencies between source files are explicit, and
|
62
|
-
|
63
|
-
Here's a simple example:
|
64
|
-
|
65
|
-
*math.rb*
|
66
|
-
```ruby
|
67
|
-
export :fib
|
68
|
-
|
69
|
-
def fib(n)
|
70
|
-
(0..1).include?(n) ? n : (fib(n - 1) + fib(n - 2))
|
71
|
-
end
|
72
|
-
```
|
73
|
-
*app.rb*
|
74
|
-
```ruby
|
75
|
-
require 'modulation'
|
76
|
-
MyMath = import('./math')
|
77
|
-
puts MyMath.fib(10)
|
78
|
-
```
|
74
|
+
So I came up with Modulation, a small gem (less than 300 LOC) that takes a
|
75
|
+
different approach to organizing Ruby code: any so-called global declarations
|
76
|
+
are hidden unless explicitly exported, and the global namespace remains
|
77
|
+
clutter-free. All dependencies between source files are explicit, visible, and
|
78
|
+
easy to understand.
|
79
79
|
|
80
80
|
## Installing Modulation
|
81
81
|
|
@@ -89,14 +89,15 @@ $ gem install modulation
|
|
89
89
|
|
90
90
|
Modulation builds on the idea of a Ruby `Module` as a
|
91
91
|
["collection of methods and constants"](https://ruby-doc.org/core-2.5.1/Module.html).
|
92
|
-
Using modulation,
|
93
|
-
method and constant declarations (usually an API for a specific,
|
94
|
-
functionality) to be shared with other modules. Modules can also
|
95
|
-
declarations from other modules.
|
92
|
+
Using modulation, each Ruby source file becomes a module. Modules usually
|
93
|
+
export method and constant declarations (usually an API for a specific,
|
94
|
+
well-defined functionality) to be shared with other modules. Modules can also
|
95
|
+
import declarations from other modules. Anything not exported remains hidden
|
96
|
+
inside the module and normally cannot be accessed from the outside.
|
96
97
|
|
97
|
-
Each
|
98
|
-
with some additional methods
|
99
|
-
|
98
|
+
Each source file is evaluated in the context of a newly-created `Module`
|
99
|
+
instance, with some additional methods for introspection and miscellaneous
|
100
|
+
operations such as [hot reloading](#reloading-modules).
|
100
101
|
|
101
102
|
### Exporting declarations
|
102
103
|
|
@@ -232,10 +233,10 @@ end
|
|
232
233
|
|
233
234
|
The special constant `MODULE` allows you to access the containing module from
|
234
235
|
nested modules or classes. This lets you call methods defined in the module's
|
235
|
-
root namespace, or otherwise introspect the module
|
236
|
+
root namespace, or otherwise introspect the module:
|
236
237
|
|
237
238
|
```ruby
|
238
|
-
export :
|
239
|
+
export :AsyncServer
|
239
240
|
|
240
241
|
# Await a promise-like callable
|
241
242
|
def await
|
@@ -245,7 +246,7 @@ def await
|
|
245
246
|
Fiber.yield
|
246
247
|
end
|
247
248
|
|
248
|
-
class
|
249
|
+
class AsyncServer < SomeTCPServer
|
249
250
|
def async_read
|
250
251
|
MODULE.await {|p| on_read {|data| p.(data)}}
|
251
252
|
end
|
@@ -264,7 +265,7 @@ end
|
|
264
265
|
|
265
266
|
::ENV = { ... }
|
266
267
|
|
267
|
-
|
268
|
+
what_is = ::THE_MEANING_OF_LIFE
|
268
269
|
```
|
269
270
|
|
270
271
|
### Unit testing modules
|
@@ -334,7 +335,7 @@ end
|
|
334
335
|
|
335
336
|
### Reloading modules
|
336
337
|
|
337
|
-
Modules can be
|
338
|
+
Modules can be reloaded at run-time for easy hot code reloading:
|
338
339
|
|
339
340
|
```ruby
|
340
341
|
require 'modulation'
|
@@ -356,8 +357,13 @@ FileWatcher.new(['lib']).watch do |fn, event|
|
|
356
357
|
end
|
357
358
|
```
|
358
359
|
|
359
|
-
|
360
|
-
|
360
|
+
> When a module is reloaded, its entire content - constants and methods - will
|
361
|
+
> be replaced. That means that any code using that module could continue to use
|
362
|
+
> it without even being aware it was reloaded, providing its API has not
|
363
|
+
> changed.
|
364
|
+
|
365
|
+
Reloading of modules with default exports is also possible. Modulation will
|
366
|
+
extend the exported value with a `#__reload!` method. The value will need to be
|
361
367
|
reassigned:
|
362
368
|
|
363
369
|
```ruby
|
@@ -424,7 +430,6 @@ MyFeature = import 'my_gem/my_feature'
|
|
424
430
|
...
|
425
431
|
```
|
426
432
|
|
427
|
-
|
428
433
|
## Why you should not use Modulation
|
429
434
|
|
430
435
|
- Modulation is not production-ready.
|
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.17'
|
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-
|
11
|
+
date: 2018-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|