modulation 0.24 → 0.25
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 +14 -8
- data/README.md +40 -23
- data/lib/modulation/core.rb +15 -0
- data/lib/modulation/ext.rb +9 -0
- 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: 05eb758bd8b1f020ab36975897629ae0246a181e75d63e92707aa2fb47945d46
|
4
|
+
data.tar.gz: f17e7568e877cfdc6d8526976f895f3595364a7755aebda382922f4bd04967d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7db683d75d02ef37ae637727537a6403cd69d506f7c6f359be5547e5f8fb05901256fb266ce4ea41dc987fc6c0976edd4f111d1ad11335a7164790a68d4a3742
|
7
|
+
data.tar.gz: be5d4e4c06983e19b1921cbb256bfa8162b6aa927eb14936f2ed8dda980715f7ac85d75eee321e0f39ae1b825fcf4be0b389c5976c476f838967d970e222fca9
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
0.25 2019-06-07
|
2
|
+
---------------
|
3
|
+
|
4
|
+
* Add `#import_map` method
|
5
|
+
|
1
6
|
0.24 2019-05-22
|
2
7
|
---------------
|
3
8
|
|
4
9
|
* Fix usage of Modulation in rake tasks
|
5
|
-
* Fix behavior when referencing missing consts in modules using
|
10
|
+
* Fix behavior when referencing missing consts in modules using `#auto_import`
|
6
11
|
|
7
12
|
0.23 2019-05-17
|
8
13
|
---------------
|
@@ -58,9 +63,9 @@
|
|
58
63
|
0.13 2018-09-06
|
59
64
|
---------------
|
60
65
|
|
61
|
-
* Evaluate module code on singleton_class instead of using
|
62
|
-
* Fix calling
|
63
|
-
* Add `rbm` binary for running ruby scripts using
|
66
|
+
* Evaluate module code on singleton_class instead of using `#extend self`
|
67
|
+
* Fix calling `#include` inside imported module
|
68
|
+
* Add `rbm` binary for running ruby scripts using `#import`
|
64
69
|
|
65
70
|
0.12 2018-08-20
|
66
71
|
---------------
|
@@ -103,19 +108,20 @@
|
|
103
108
|
--------------
|
104
109
|
|
105
110
|
* Add support for using gems as imported modules (experimental feature)
|
106
|
-
* Add Modulation.full_trace
|
107
|
-
* Fix Modulation.transform_export_default_value
|
111
|
+
* Add `Modulation.full_trace!` method for getting full backtrace on errors
|
112
|
+
* Fix `Modulation.transform_export_default_value`
|
108
113
|
* Change name to *Modulation*
|
109
114
|
|
110
115
|
0.5.1 2018-07-20
|
111
116
|
----------------
|
112
117
|
|
113
|
-
* Fix extend_from
|
118
|
+
* Fix `#extend_from`, `#include_from` to work with ruby 2.4
|
114
119
|
|
115
120
|
0.5 2018-07-19
|
116
121
|
--------------
|
117
122
|
|
118
|
-
* Add extend_from
|
123
|
+
* Add `#extend_from`, `#include_from` to include imported methods in classes
|
124
|
+
and modules
|
119
125
|
|
120
126
|
0.4 2018-07-19
|
121
127
|
--------------
|
data/README.md
CHANGED
@@ -28,21 +28,21 @@ a functional style, minimizing boilerplate code.
|
|
28
28
|
## Rationale
|
29
29
|
|
30
30
|
You're probably asking yourself "what the ****?" , but when your Ruby app grows
|
31
|
-
and is split into multiple files loaded using
|
31
|
+
and is split into multiple files loaded using `#require`, you'll soon hit some
|
32
32
|
issues:
|
33
33
|
|
34
|
-
- Once a file is
|
34
|
+
- Once a file is `#require`d, any class, module or constant in it is available
|
35
35
|
to any other file in your codebase. All "globals" (classes, modules,
|
36
36
|
constants) are loaded, well, globally, in a single namespace. Name conflicts
|
37
37
|
are easy in Ruby.
|
38
38
|
- To avoid class name conflicts, classes need to be nested under a single
|
39
39
|
hierarchical tree, sometime reaching 4 levels or more. Just look at Rails.
|
40
|
-
- Since a
|
40
|
+
- Since a `#require`d class or module can be loaded in any file and then made
|
41
41
|
available to all files, it's easy to lose track of where it was loaded, and
|
42
42
|
where it is used.
|
43
43
|
- There's no easy way to hide implementation-specific classes or methods. Yes,
|
44
|
-
there's
|
45
|
-
|
44
|
+
there's `#private`, `#private_constant` etc, but by default everything is
|
45
|
+
`#public`!
|
46
46
|
- Writing reusable functional code requires wrapping it in modules using
|
47
47
|
`class << self`, `def self.foo ...`, `extend self` or `include Singleton`
|
48
48
|
(the pain of implementing singletons in Ruby has been
|
@@ -54,7 +54,7 @@ issues:
|
|
54
54
|
> name collision. Hopefully, the present gem could contribute to an eventual
|
55
55
|
> "official" API.
|
56
56
|
|
57
|
-
Personally, I have found that managing dependencies with
|
57
|
+
Personally, I have found that managing dependencies with `#require` in large
|
58
58
|
codebases is... not as elegant or painfree as I would expect from a
|
59
59
|
first-class development environment. I also wanted to have a better solution
|
60
60
|
for writing in a functional style.
|
@@ -108,7 +108,7 @@ operations such as [hot reloading](#reloading-modules).
|
|
108
108
|
|
109
109
|
### Exporting declarations
|
110
110
|
|
111
|
-
Any class, module or constant be exported using
|
111
|
+
Any class, module or constant be exported using `#export`:
|
112
112
|
|
113
113
|
```ruby
|
114
114
|
export :User, :Session
|
@@ -146,7 +146,7 @@ puts Seq.fib(10)
|
|
146
146
|
|
147
147
|
### Importing declarations
|
148
148
|
|
149
|
-
Declarations from another module can be imported using
|
149
|
+
Declarations from another module can be imported using `#import`:
|
150
150
|
|
151
151
|
```ruby
|
152
152
|
require 'modulation'
|
@@ -170,19 +170,36 @@ user = User.new(...)
|
|
170
170
|
```
|
171
171
|
|
172
172
|
> **Note about paths**: module paths are always relative to the file
|
173
|
-
> calling the
|
173
|
+
> calling the `#import` method, just like `#require_relative`.
|
174
174
|
|
175
175
|
### Importing all source files in a directory
|
176
176
|
|
177
|
-
To load all source files in a directory you can use
|
177
|
+
To load all source files in a directory you can use `#import_all`:
|
178
178
|
|
179
179
|
```ruby
|
180
|
-
import_all('./ext') # will load ./ext/kernel, ./ext/socket etc
|
180
|
+
import_all('./ext') # will load ./ext/kernel.rb, ./ext/socket.rb etc
|
181
|
+
```
|
182
|
+
|
183
|
+
Groups of modules providing a uniform interface can also be loaded using
|
184
|
+
`#import_map`:
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
API = import_map('./math_api') #=> hash mapping filenames to modules
|
188
|
+
API.keys #=> ['add', 'mul', 'sub', 'div']
|
189
|
+
API['add'] #=> add module
|
190
|
+
```
|
191
|
+
|
192
|
+
The `#import_map` takes an optional block to transform hash keys:
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
API = import_map('./math_api') { |name, mod| name.to_sym }
|
196
|
+
API.keys #=> [:add, :mul, :sub, :div]
|
197
|
+
API[:add] #=> add module
|
181
198
|
```
|
182
199
|
|
183
200
|
### Importing methods into classes and modules
|
184
201
|
|
185
|
-
Modulation provides the
|
202
|
+
Modulation provides the `#extend_from` and `#include_from` methods to include
|
186
203
|
imported methods in classes and modules:
|
187
204
|
|
188
205
|
```ruby
|
@@ -205,7 +222,7 @@ end
|
|
205
222
|
5.seq(:fib)
|
206
223
|
```
|
207
224
|
|
208
|
-
The
|
225
|
+
The `#include_from` method accepts an optional list of symbols to import:
|
209
226
|
|
210
227
|
```ruby
|
211
228
|
class Integer
|
@@ -218,7 +235,7 @@ end
|
|
218
235
|
### Default exports
|
219
236
|
|
220
237
|
A module may wish to expose just a single class or constant, in which case it
|
221
|
-
can use
|
238
|
+
can use `#export_default`:
|
222
239
|
|
223
240
|
*user.rb*
|
224
241
|
```ruby
|
@@ -295,7 +312,7 @@ what_is = ::THE_MEANING_OF_LIFE
|
|
295
312
|
|
296
313
|
### Unit testing modules
|
297
314
|
|
298
|
-
Methods and constants that are not exported can be tested using the
|
315
|
+
Methods and constants that are not exported can be tested using the `#__expose!`
|
299
316
|
method. Thus you can keep implementation details hidden, while being able to
|
300
317
|
easily test them:
|
301
318
|
|
@@ -380,7 +397,7 @@ end
|
|
380
397
|
> lazy-loaded constant from the module's top namespace, use the `MODULE`
|
381
398
|
> namespace, as shown above.
|
382
399
|
|
383
|
-
The
|
400
|
+
The `#auto_import` method can also take a hash mapping constant names to paths.
|
384
401
|
This is especially useful when multiple concerns are grouped under a single
|
385
402
|
namespace:
|
386
403
|
|
@@ -440,7 +457,7 @@ settings = settings.__reload!
|
|
440
457
|
|
441
458
|
Modulation can be used to write gems, providing fine-grained control over your
|
442
459
|
gem's public APIs and letting you hide any implementation details. In order to
|
443
|
-
allow loading a gem using either
|
460
|
+
allow loading a gem using either `#require` or `#import`, code your gem's main
|
444
461
|
file normally, but add `require 'modulation/gem'` at the top, and export your
|
445
462
|
gem's main namespace as a default export, e.g.:
|
446
463
|
|
@@ -458,7 +475,7 @@ end
|
|
458
475
|
|
459
476
|
## Importing gems using Modulation
|
460
477
|
|
461
|
-
Gems written using modulation can also be loaded using
|
478
|
+
Gems written using modulation can also be loaded using `#import`. If modulation
|
462
479
|
does not find the module specified by the given relative path, it will attempt
|
463
480
|
to load a gem by the same name. It is also possible to load specific files
|
464
481
|
inside modules by specifying a sub-path:
|
@@ -468,9 +485,9 @@ require 'modulation'
|
|
468
485
|
MyFeature = import 'my_gem/my_feature'
|
469
486
|
```
|
470
487
|
|
471
|
-
> **Note**: Since there's not much of a point in
|
472
|
-
> Modulation to export symbols, Modulation will refuse to import any gem
|
473
|
-
> does not depend on Modulation.
|
488
|
+
> **Note**: Since there's not much of a point in `#import`ing gems that do not
|
489
|
+
> use Modulation to export symbols, Modulation will refuse to import any gem
|
490
|
+
> that does not depend on Modulation.
|
474
491
|
|
475
492
|
## Coding style recommendations
|
476
493
|
|
@@ -480,8 +497,8 @@ MyFeature = import 'my_gem/my_feature'
|
|
480
497
|
Settings = import('./settings')
|
481
498
|
```
|
482
499
|
|
483
|
-
* Place your exports at the top of your module, followed by
|
484
|
-
followed by
|
500
|
+
* Place your exports at the top of your module, followed by `#require`s,
|
501
|
+
followed by `#import`s:
|
485
502
|
|
486
503
|
```ruby
|
487
504
|
export :foo, :bar, :baz
|
data/lib/modulation/core.rb
CHANGED
@@ -56,6 +56,21 @@ module Modulation
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
# Imports all source files in given directory, returning a hash mapping
|
60
|
+
# filenames to modules
|
61
|
+
# @ param path [String] relative directory path
|
62
|
+
# @param caller_location [String] caller location
|
63
|
+
# @return [Hash] hash mapping filenames to modules
|
64
|
+
def import_map(path, caller_location = caller(1..1).first)
|
65
|
+
abs_path = Paths.absolute_dir_path(path, caller_location)
|
66
|
+
Dir["#{abs_path}/**/*.rb"].each_with_object({}) do |fn, h|
|
67
|
+
mod = @loaded_modules[fn] || create_module_from_file(fn)
|
68
|
+
name = File.basename(fn) =~ /^(.+)\.rb$/ && $1
|
69
|
+
name = yield name, mod if block_given?
|
70
|
+
h[name] = mod
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
59
74
|
# Adds all or part of a module's methods to a target object
|
60
75
|
# If no symbols are given, all methods are added
|
61
76
|
# @param mod [Module] imported module
|
data/lib/modulation/ext.rb
CHANGED
@@ -17,6 +17,15 @@ module Kernel
|
|
17
17
|
def import_all(path, caller_location = caller(1..1).first)
|
18
18
|
Modulation.import_all(path, caller_location)
|
19
19
|
end
|
20
|
+
|
21
|
+
# Imports all modules in given directory, returning a hash mapping filenames
|
22
|
+
# to modules
|
23
|
+
# @param path [String] directory path
|
24
|
+
# @param caller_location [String] caller location
|
25
|
+
# @return [Hash] hash mapping filenames to module objects
|
26
|
+
def import_map(path, caller_location = caller(1..1).first, &block)
|
27
|
+
Modulation.import_map(path, caller_location, &block)
|
28
|
+
end
|
20
29
|
end
|
21
30
|
|
22
31
|
# Module extensions
|
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.25'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|