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