modulation 0.34 → 1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b35f333f45c8017d3fd44700fc5cd3d16dcdd575be012b3f86f2af17c2fcaef
4
- data.tar.gz: de1b7cf9b6cd1d39080fd2ef971d99b23fa2b91f18a90db2bbcacf9debfdd7c7
3
+ metadata.gz: a81a52fa3760bfbda94193a1e1de70bd498dd8112455ec774fc9b5735bf8fbfa
4
+ data.tar.gz: 37e1ca88843461ccc8e3d137e4c686d3969641a381210ec7cb40a0215ec184c4
5
5
  SHA512:
6
- metadata.gz: 914789190308c5b9133d4bc3f2a5b6209fe9123ba1d984e7e77b1062f6392b9cb09a4db32b44b631db631080e655bf7dfb32b1955693eb39d0573a85487dba4d
7
- data.tar.gz: 2cba7fed4ae3c0a36abb3f8a2f1505074191ba52cfa7510022060730accf39a932e00b6e3323e7b0643ac8e6932f6046be4e10fa7bff435004a6ceb75492bd68
6
+ metadata.gz: 2f57985001fea20c87d1b8a7a1e06244fd21a52a5e1830177ee3d379e9cb81913a03dde161fdcc78fe4d7f14d8a486def00058cca2b01b8f8e233cb70b413107
7
+ data.tar.gz: 0cbc73dc2b7684a7b63fe50c6d505175f78b894fa0b043991ae4591cfc38e1a3849c3ac6c4b7f50e1cdb190f8570e6e00cd4405cb3f95d9494aff7485cf64437
@@ -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
- - **[Dependency mocking](#mocking-dependencies)** facilitates testing.
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 dependencies
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
- This section will be expanded on in a future release.
812
+ ### Kernel
784
813
 
785
- #### `__module_info`
814
+ #### `Kernel#auto_import_map(path, options = {})`
786
815
 
787
- ### `__reload!`
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
- #### `alias_method_once()`
819
+ #### `Kernel#import(path)`
790
820
 
791
- #### `auto_import()`
821
+ #### `Kernel#import_all(path)`
792
822
 
793
- #### `auto_import_map()`
823
+ #### `Kernel#import_map(path, options = {})`
794
824
 
795
- #### `export()`
825
+ ### Module
796
826
 
797
- #### `export_default()`
827
+ #### `Module#__module_info`
798
828
 
799
- #### `export_from_receiver()`
829
+ Returns a hash containing information about the module. This currently includes
830
+ the following entries:
800
831
 
801
- #### `extend_from()`
832
+ location|Absolute module file path
833
+ exported_symbols|Array containing all symbols exported by the module
802
834
 
803
- #### `import()`
835
+ ### `Module#__reload!`
804
836
 
805
- #### `import_all()`
837
+ #### `Module#alias_method_once(new_name, old_name)`
806
838
 
807
- #### `import_map()`
839
+ #### `Module#auto_import(sym, path)`
808
840
 
809
- #### `include_from()`
841
+ #### `Module#export(*symbols)`
810
842
 
811
- #### `Modulation.full_backtrace!`
843
+ #### `Module#export_default(value)`
844
+
845
+ #### `Module#export_from_receiver(receiver)`
812
846
 
813
- #### `Modulation.reload()`
847
+ #### `Module#extend_from(path)`
814
848
 
815
- #### `MODULE`
849
+ #### `Module#include_from(path, *symbols)`
850
+
851
+ #### `Module::MODULE`
852
+
853
+ ### Modulation
854
+
855
+ #### `Modulation.full_backtrace!`
816
856
 
817
- #### `MODULE.__module_info`
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: :export,
35
- args: symbols,
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: :export_from_receiver,
50
- args: name,
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.call mod
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
- if find(info[:location])
31
- info[:source] = read_file(info[:location])
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 = /^@(.+)$/.freeze
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 do |k, v|
20
- if k =~ Modulation::RE_CONST
21
- m.const_set(k, v)
22
- elsif k =~ RE_ATTR
23
- m.instance_variable_set(k, v)
24
- elsif v.respond_to?(:to_proc)
25
- s.send(:define_method, k) { |*args| instance_exec(*args, &v) }
26
- else
27
- s.send(:define_method, k) { v }
28
- end
29
- end
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
- m = Modulation::Builder.make(source: str)
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
- zipped = Zlib::Deflate.deflate(content)
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
- packed_dictionary = Zlib::Deflate.deflate(dictionary.inspect)
61
- data << packed_dictionary
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
- dict_offset: last_offset,
65
- data: data
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, entry_point)
67
+ def generate_bootstrap(package_info, _entry_point)
70
68
  format(
71
69
  bootstrap_template,
72
70
  modulation_version: Modulation::VERSION,
@@ -16,10 +16,14 @@ module Modulation
16
16
 
17
17
  def tags
18
18
  @tags ||= {
19
- 'modulation' => File.join(Modulation::DIR, 'modulation/modules')
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Modulation
4
- VERSION = '0.34'
4
+ VERSION = '1.0'
5
5
  end
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.34'
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-14 00:00:00.000000000 Z
11
+ date: 2019-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest