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