modulation 0.34 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -2
- data/README.md +60 -20
- data/lib/modulation/module_mixin.rb +5 -5
- data/lib/modulation/modules/bootstrap.rb +3 -4
- data/lib/modulation/modules/cli.rb +10 -9
- data/lib/modulation/modules/creator.rb +15 -13
- data/lib/modulation/modules/packer.rb +14 -16
- data/lib/modulation/paths.rb +5 -1
- 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: a81a52fa3760bfbda94193a1e1de70bd498dd8112455ec774fc9b5735bf8fbfa
|
4
|
+
data.tar.gz: 37e1ca88843461ccc8e3d137e4c686d3969641a381210ec7cb40a0215ec184c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f57985001fea20c87d1b8a7a1e06244fd21a52a5e1830177ee3d379e9cb81913a03dde161fdcc78fe4d7f14d8a486def00058cca2b01b8f8e233cb70b413107
|
7
|
+
data.tar.gz: 0cbc73dc2b7684a7b63fe50c6d505175f78b894fa0b043991ae4591cfc38e1a3849c3ac6c4b7f50e1cdb190f8570e6e00cd4405cb3f95d9494aff7485cf64437
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
1.0 2019-10-18
|
2
|
+
--------------
|
3
|
+
|
4
|
+
* Cleanup code
|
5
|
+
* Obfuscate bootstrap dictionary code in packages
|
6
|
+
* Move packer, bootstrap, CLI, creator code into stock modules
|
7
|
+
|
1
8
|
0.34 2019-10-14
|
2
9
|
---------------
|
3
10
|
|
4
|
-
* Obfuscate bootstrapping code in packages
|
5
|
-
* Move packer, bootstrap, CLI, creator code into stock modules
|
6
11
|
* Improve README
|
7
12
|
|
8
13
|
0.33 2019-10-02
|
data/README.md
CHANGED
@@ -34,11 +34,13 @@ a functional style, minimizing boilerplate code.
|
|
34
34
|
[importing](#importing-declarations) of methods and constants** lets you
|
35
35
|
control the public interface for each module, as well as keep track of all
|
36
36
|
dependencies in your code.
|
37
|
+
- **[Tagged paths](#using-tags-to-designate-common-subdirectories)** simplify
|
38
|
+
the management of dependencies in large applications.
|
37
39
|
- **[Lazy Loading](#lazy-loading)** improves start up time and memory
|
38
40
|
consumption.
|
39
41
|
- **[Hot module reloading](#reloading-modules)** streamlines your development
|
40
42
|
process.
|
41
|
-
- **[
|
43
|
+
- **[Module mocking](#mocking-modules)** facilitates testing.
|
42
44
|
- **[Dependency introspection](#dependency-introspection)** lets you introspect
|
43
45
|
your dependencies at runtime.
|
44
46
|
- **[Application packing](#packing-applications-with-modulation)** lets you
|
@@ -472,7 +474,7 @@ class FibTest < Minitest::Test
|
|
472
474
|
end
|
473
475
|
```
|
474
476
|
|
475
|
-
### Mocking
|
477
|
+
### Mocking modules
|
476
478
|
|
477
479
|
Modules loaded by Modulation can be easily mocked when running tests or specs,
|
478
480
|
using `Modulation.mock`:
|
@@ -503,6 +505,9 @@ class UserControllerTest < Minitest::Test
|
|
503
505
|
end
|
504
506
|
```
|
505
507
|
|
508
|
+
`Modulation.mock` accepts a module path and a receiver, and the module stays
|
509
|
+
mocked within the given block.
|
510
|
+
|
506
511
|
### Lazy Loading
|
507
512
|
|
508
513
|
Modulation allows the use of lazy-loaded modules - loading of modules only once
|
@@ -583,6 +588,30 @@ settings = import('settings')
|
|
583
588
|
settings = settings.__reload!
|
584
589
|
```
|
585
590
|
|
591
|
+
Please note that Modulation does not include a directory watcher that
|
592
|
+
automatically reloads changed modules. This is due to multiple considerations
|
593
|
+
that include the chosen threading model, or the reactor engine in use, or even
|
594
|
+
the chosen solution for watching files (whether it's an external gem or an
|
595
|
+
internal tool).
|
596
|
+
|
597
|
+
It is, however, quite trivial to watch files using
|
598
|
+
[`directory_watcher`](https://rubygems.org/gems/directory_watcher/):
|
599
|
+
|
600
|
+
```ruby
|
601
|
+
require 'directory_watcher'
|
602
|
+
|
603
|
+
dw = DirectoryWatcher.new 'lib', glob: '**/*.rb', interval: 2, pre_load: true
|
604
|
+
dw.add_observer do |*events|
|
605
|
+
events.each do |e|
|
606
|
+
next unless e.type == :modified
|
607
|
+
|
608
|
+
Modulation.reload e.path
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
dw.start
|
613
|
+
```
|
614
|
+
|
586
615
|
### Retaining state between reloads
|
587
616
|
|
588
617
|
Before a module is reloaded, all of its methods and constants are removed. In
|
@@ -780,41 +809,52 @@ end
|
|
780
809
|
|
781
810
|
## API Reference
|
782
811
|
|
783
|
-
|
812
|
+
### Kernel
|
784
813
|
|
785
|
-
#### `
|
814
|
+
#### `Kernel#auto_import_map(path, options = {})`
|
786
815
|
|
787
|
-
|
816
|
+
Returns a hash mapping keys to corresponding module files inside the given
|
817
|
+
directory path. Modules are loaded automatically upon accessing hash keys.
|
788
818
|
|
789
|
-
#### `
|
819
|
+
#### `Kernel#import(path)`
|
790
820
|
|
791
|
-
#### `
|
821
|
+
#### `Kernel#import_all(path)`
|
792
822
|
|
793
|
-
#### `
|
823
|
+
#### `Kernel#import_map(path, options = {})`
|
794
824
|
|
795
|
-
|
825
|
+
### Module
|
796
826
|
|
797
|
-
#### `
|
827
|
+
#### `Module#__module_info`
|
798
828
|
|
799
|
-
|
829
|
+
Returns a hash containing information about the module. This currently includes
|
830
|
+
the following entries:
|
800
831
|
|
801
|
-
|
832
|
+
location|Absolute module file path
|
833
|
+
exported_symbols|Array containing all symbols exported by the module
|
802
834
|
|
803
|
-
|
835
|
+
### `Module#__reload!`
|
804
836
|
|
805
|
-
#### `
|
837
|
+
#### `Module#alias_method_once(new_name, old_name)`
|
806
838
|
|
807
|
-
#### `
|
839
|
+
#### `Module#auto_import(sym, path)`
|
808
840
|
|
809
|
-
#### `
|
841
|
+
#### `Module#export(*symbols)`
|
810
842
|
|
811
|
-
#### `
|
843
|
+
#### `Module#export_default(value)`
|
844
|
+
|
845
|
+
#### `Module#export_from_receiver(receiver)`
|
812
846
|
|
813
|
-
#### `
|
847
|
+
#### `Module#extend_from(path)`
|
814
848
|
|
815
|
-
#### `
|
849
|
+
#### `Module#include_from(path, *symbols)`
|
850
|
+
|
851
|
+
#### `Module::MODULE`
|
852
|
+
|
853
|
+
### Modulation
|
854
|
+
|
855
|
+
#### `Modulation.full_backtrace!`
|
816
856
|
|
817
|
-
#### `
|
857
|
+
#### `Modulation.reload`
|
818
858
|
|
819
859
|
## Why you should not use Modulation
|
820
860
|
|
@@ -31,8 +31,8 @@ module Modulation
|
|
31
31
|
|
32
32
|
@__export_directives ||= []
|
33
33
|
@__export_directives << {
|
34
|
-
method:
|
35
|
-
args:
|
34
|
+
method: :export,
|
35
|
+
args: symbols,
|
36
36
|
export_caller: caller
|
37
37
|
}
|
38
38
|
end
|
@@ -46,8 +46,8 @@ module Modulation
|
|
46
46
|
|
47
47
|
@__export_directives ||= []
|
48
48
|
@__export_directives << {
|
49
|
-
method:
|
50
|
-
args:
|
49
|
+
method: :export_from_receiver,
|
50
|
+
args: name,
|
51
51
|
export_caller: caller
|
52
52
|
}
|
53
53
|
end
|
@@ -113,7 +113,7 @@ module Modulation
|
|
113
113
|
|
114
114
|
def __traverse_dependencies(&block)
|
115
115
|
__dependencies.each do |mod|
|
116
|
-
block.
|
116
|
+
block.(mod)
|
117
117
|
if mod.respond_to?(:__traverse_dependencies)
|
118
118
|
mod.__traverse_dependencies(&block)
|
119
119
|
end
|
@@ -27,9 +27,8 @@ def patch_builder
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def transform_module_info(info)
|
30
|
-
|
31
|
-
|
32
|
-
end
|
30
|
+
location = info[:location]
|
31
|
+
info[:source] = read_file(location) if location
|
33
32
|
info
|
34
33
|
end
|
35
34
|
|
@@ -46,4 +45,4 @@ def read_file(path)
|
|
46
45
|
(offset, length) = @dictionary[path]
|
47
46
|
@data.seek(@data_offset + offset)
|
48
47
|
Zlib::Inflate.inflate(@data.read(length))
|
49
|
-
end
|
48
|
+
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
export_default :CLI
|
4
4
|
|
5
|
+
# Command line interface functionality
|
5
6
|
class CLI
|
6
7
|
def initialize(argv)
|
7
8
|
@argv = argv
|
@@ -25,15 +26,15 @@ class CLI
|
|
25
26
|
cleanup_backtrace(e)
|
26
27
|
raise e
|
27
28
|
end
|
28
|
-
|
29
|
+
|
29
30
|
def run_file(arg)
|
30
31
|
fn, method = filename_and_method_from_arg(arg)
|
31
32
|
mod = import(File.expand_path(fn))
|
32
33
|
mod.send(method) if method
|
33
34
|
end
|
34
|
-
|
35
|
+
|
35
36
|
FILENAME_AND_METHOD_RE = /^([^\:]+)\:(.+)$/.freeze
|
36
|
-
|
37
|
+
|
37
38
|
def filename_and_method_from_arg(arg)
|
38
39
|
if arg =~ FILENAME_AND_METHOD_RE
|
39
40
|
match = Regexp.last_match
|
@@ -42,14 +43,14 @@ class CLI
|
|
42
43
|
[arg, :main]
|
43
44
|
end
|
44
45
|
end
|
45
|
-
|
46
|
+
|
46
47
|
BACKTRACE_RE = /^(#{Modulation::DIR})|(bin\/mdl)/.freeze
|
47
|
-
|
48
|
+
|
48
49
|
def cleanup_backtrace(error)
|
49
50
|
backtrace = error.backtrace.reject { |l| l =~ BACKTRACE_RE }
|
50
51
|
error.set_backtrace(backtrace)
|
51
52
|
end
|
52
|
-
|
53
|
+
|
53
54
|
def collect_deps(path, array)
|
54
55
|
if File.directory?(path)
|
55
56
|
Dir["#{path}/**/*.rb"].each { |fn| collect_deps(fn, array) }
|
@@ -61,17 +62,17 @@ class CLI
|
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
64
|
-
|
65
|
+
|
65
66
|
def deps
|
66
67
|
paths = []
|
67
68
|
@argv.each { |arg| collect_deps(arg, paths) }
|
68
69
|
puts(*paths)
|
69
70
|
end
|
70
|
-
|
71
|
+
|
71
72
|
def pack
|
72
73
|
STDOUT << import('@modulation/packer').pack(@argv, hide_filenames: true)
|
73
74
|
end
|
74
|
-
|
75
|
+
|
75
76
|
def version
|
76
77
|
puts "Modulation version #{Modulation::VERSION}"
|
77
78
|
end
|
@@ -4,7 +4,7 @@ export :from_block,
|
|
4
4
|
:from_hash,
|
5
5
|
:from_string
|
6
6
|
|
7
|
-
RE_ATTR
|
7
|
+
RE_ATTR = /^@(.+)$/.freeze
|
8
8
|
|
9
9
|
def from_block(block)
|
10
10
|
Module.new.tap { |m| m.instance_eval(&block) }
|
@@ -16,20 +16,22 @@ end
|
|
16
16
|
def from_hash(hash)
|
17
17
|
Module.new.tap do |m|
|
18
18
|
s = m.singleton_class
|
19
|
-
hash.each
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
19
|
+
hash.each { |k, v| process_hash_entry(k, v, m, s) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def process_hash_entry(key, value, mod, singleton)
|
24
|
+
if key =~ Modulation::RE_CONST
|
25
|
+
mod.const_set(key, value)
|
26
|
+
elsif key =~ RE_ATTR
|
27
|
+
mod.instance_variable_set(key, value)
|
28
|
+
elsif value.respond_to?(:to_proc)
|
29
|
+
singleton.send(:define_method, key) { |*args| instance_exec(*args, &value) }
|
30
|
+
else
|
31
|
+
singleton.send(:define_method, key) { value }
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
35
|
def from_string(str)
|
34
|
-
|
36
|
+
Modulation::Builder.make(source: str)
|
35
37
|
end
|
@@ -44,29 +44,27 @@ def generate_packed_data(deps, entry_point_filename)
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def pack_files(files, entry_point_filename)
|
47
|
+
dictionary = { entry_point: entry_point_filename }
|
47
48
|
data = (+'').encode('ASCII-8BIT')
|
48
49
|
last_offset = 0
|
49
|
-
dictionary = {
|
50
|
-
entry_point: entry_point_filename
|
51
|
-
}
|
52
50
|
files.each_with_object(dictionary) do |(path, content), dict|
|
53
|
-
|
54
|
-
size = zipped.bytesize
|
55
|
-
|
56
|
-
data << zipped
|
57
|
-
dict[path] = [last_offset, size]
|
58
|
-
last_offset += size
|
51
|
+
last_offset = add_packed_file(path, content, data, dict, last_offset)
|
59
52
|
end
|
60
|
-
|
61
|
-
|
53
|
+
data << Zlib::Deflate.deflate(dictionary.inspect)
|
54
|
+
|
55
|
+
{ dict_offset: last_offset, data: data }
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_packed_file(path, content, data, dict, last_offset)
|
59
|
+
zipped = Zlib::Deflate.deflate(content)
|
60
|
+
size = zipped.bytesize
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
}
|
62
|
+
data << zipped
|
63
|
+
dict[path] = [last_offset, size]
|
64
|
+
last_offset + size
|
67
65
|
end
|
68
66
|
|
69
|
-
def generate_bootstrap(package_info,
|
67
|
+
def generate_bootstrap(package_info, _entry_point)
|
70
68
|
format(
|
71
69
|
bootstrap_template,
|
72
70
|
modulation_version: Modulation::VERSION,
|
data/lib/modulation/paths.rb
CHANGED
@@ -16,10 +16,14 @@ module Modulation
|
|
16
16
|
|
17
17
|
def tags
|
18
18
|
@tags ||= {
|
19
|
-
'modulation' =>
|
19
|
+
'modulation' => modules_path
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
|
+
def modules_path
|
24
|
+
File.join(Modulation::DIR, 'modulation/modules')
|
25
|
+
end
|
26
|
+
|
23
27
|
def add_tags(new_tags, caller_location)
|
24
28
|
caller_file = caller_location[CALLER_FILE_REGEXP, 1]
|
25
29
|
caller_dir = caller_file ? File.dirname(caller_file) : nil
|
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: '1.0'
|
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-10-
|
11
|
+
date: 2019-10-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|