alki-reload 0.1.0 → 0.2.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
  SHA1:
3
- metadata.gz: 81d6fa79f6cda460001792bc044bb0e249f2875a
4
- data.tar.gz: 684d8997a8faf0aa288373adf5f2e94797e1cf7e
3
+ metadata.gz: b05597e13de69db0fcbc34fd150c89fde3647a24
4
+ data.tar.gz: 6e7161d23ae9d232b7e7c0e5309ca6e3b49871a6
5
5
  SHA512:
6
- metadata.gz: 5f98c6a378a333915e1520e88e1d6253d02bf467f53a5b674b2d5791386b20de8b8ffe8cda59fe7ccb1659c53ca85cbb44d692a6c6a3f0d643732146028ac43d
7
- data.tar.gz: c5bcbb7022610e6b1e27f1257c9b91d324cbe68b24a2c8cbcc95c19fb80fd9d43858b6b01d93346607d237b20b21e25df2b938cf8d427ecf068c82e216d043f2
6
+ metadata.gz: 672a296eadf628c9cbb3a5a3f53766d1c67d48b22e30ff53d865b89f151897197219643bb336c2f892333aed1671a230948763bd1dc34eed0a13e83067ef19c0
7
+ data.tar.gz: 751e2cc7bcb01466edb10ddb95d15017b2e3f53732d99f75f4e6eaab333a7de28c8ec629955bc8fe625c9cbc9f9438250ed2728d624af3ec03c9dd9e2e522ed5
data/README.adoc ADDED
@@ -0,0 +1,162 @@
1
+ = Alki::Reload
2
+
3
+ Provides auto-reload feature to Alki projects. Like the auto-reload feature in Ruby on Rails, when
4
+ enabled it will monitor source files and whenever a change is detected, will reload the project.
5
+
6
+ == Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ [source,ruby]
11
+ ----
12
+ gem 'alki-reload'
13
+ ----
14
+
15
+ And then execute:
16
+
17
+ [source]
18
+ ----
19
+ $ bundle
20
+ ----
21
+
22
+ Or install it yourself as:
23
+
24
+ [source]
25
+ ----
26
+ $ gem install alki-reload
27
+ ----
28
+
29
+ == Usage
30
+
31
+ To use Alki::Reload in an Alki project, it must be mounted in the assembly. By default, Alki::Reload
32
+ will not actively watch files or actively hook into services. Setting `enable` to true will enable both.
33
+
34
+ .config/assembly.rb
35
+ ```ruby
36
+ Alki do
37
+ mount :reloader, 'alki/reload' do
38
+ set(:enable) { true }
39
+ end
40
+ # ...
41
+ end
42
+ ```
43
+
44
+ ### Conditional usage
45
+
46
+ Because enabling reload can have a performance impact, typically it's only enabled when in some sort
47
+ of development mode.
48
+
49
+ .config/assembly.rb
50
+ ```ruby
51
+ Alki do
52
+ set(:development?) { ENV['APP_ENV'] != 'production' }
53
+
54
+ mount :reloader, 'alki/reload' do
55
+ set(:enable) { development? }
56
+ end
57
+ # ...
58
+ end
59
+ ```
60
+
61
+ ### Main Loops
62
+
63
+ A problem that naturally comes up is how to reload an application, while the application is running.
64
+ Most applications, when running, spend most of their time inside a "main loop". If it's a server,
65
+ it might be the loop listening for incoming data, if it's a console application it might be the loop
66
+ waiting for user input.
67
+
68
+ Because the main loop is always running, there is never an opportunity to reload it. Alki::Reload
69
+ provides a feature to help work around this.
70
+
71
+ First off, because the service the main loop is in can't be reloaded, it should be made as small and
72
+ simple as possible, offloading all other functionality into secondary services that it takes as
73
+ dependencies.
74
+
75
+ Second, it should be tagged with a `main_loop` tag. By tagging your main loop service, Alki::Reload will
76
+ actively hook into the service and wrap it's dependencies with wrapper objects that will pick up the
77
+ new version of those dependencies whenever the project is reloaded.
78
+
79
+ Alki::Loader must be enabled for this feature to be active.
80
+
81
+ .config/assembly.rb
82
+ ```ruby
83
+ Alki do
84
+ mount :reloader, 'alki/reload', enable: true
85
+
86
+ set :prompt, "> "
87
+ service :handler do
88
+ -> line { puts line }
89
+ end
90
+
91
+ tag :main_loop
92
+ service :main do
93
+ require 'readline_loop'
94
+ ReadlineLoop.new prompt, handler
95
+ end
96
+ # ...
97
+ end
98
+ ```
99
+
100
+ .lib/readline_loop.rb
101
+ ```ruby
102
+ require 'readline'
103
+ class ReadlineLoop
104
+ def initialize(prompt, handler)
105
+ @prompt = prompt
106
+ @handler = handler
107
+ end
108
+
109
+ def run
110
+ while line = Readline.readline(@prompt,true)
111
+ @handler.call line
112
+ end
113
+ end
114
+ end
115
+ ```
116
+
117
+ In this example, our main loop is `main.run`. Because the `main` service is tagged even while it
118
+ is running the prompt and handler can be changed and reloaded.
119
+
120
+ ### Watched Directories
121
+
122
+ By default, `lib`, `config` and any files or directories configured in
123
+ https://github.com/alki-project/alki-loader[Alki::Loader] are watched.
124
+
125
+ Additional directories can be added by overriding the dirs element. Additional directories must also
126
+ be in `$LOAD_PATH`.
127
+
128
+ .config/assembly.rb
129
+ ```ruby
130
+ Alki do
131
+ mount :reloader, 'alki/reload' do
132
+ set(:enable) { true }
133
+ set(:dirs) { original.dirs + ['app'] }
134
+ end
135
+ # ...
136
+ end
137
+ ```
138
+
139
+ ### Manual Reloading
140
+
141
+ In addition to watching for filesystem changes, a project can be reloaded manually by calling
142
+ the `reload` func in the reloader. This works even when the reloader is not enabled.
143
+
144
+ .config/assembly.rb
145
+ ```ruby
146
+ Alki do
147
+ mount :reloader, 'alki/reload'
148
+ # ...
149
+ end
150
+ ```
151
+
152
+ ```ruby
153
+ instance.reloader.reload # reload instance
154
+ ```
155
+
156
+ == Contributing
157
+
158
+ Bug reports and pull requests are welcome on GitHub at https://github.com/alki-project/alki-reload. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the http://contributor-covenant.org[Contributor Covenant] code of conduct.
159
+
160
+ == License
161
+
162
+ The gem is available as open source under the terms of the http://opensource.org/licenses/MIT[MIT License].
data/alki-reload.gemspec CHANGED
@@ -23,5 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 1.13"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
25
  spec.add_dependency "listen", "~> 3.0"
26
- spec.add_dependency "alki", "~> 0.9", ">= 0.9.1"
26
+ spec.add_dependency "alki", "~> 0.10"
27
27
  end
data/config/assembly.rb CHANGED
@@ -3,7 +3,15 @@ Alki do
3
3
  root.assembly_instance.__reload__
4
4
  end
5
5
 
6
- set :watch, false
6
+ set :enable, false
7
+
8
+ set :main_loops do
9
+ enable
10
+ end
11
+
12
+ set :watch do
13
+ enable
14
+ end
7
15
 
8
16
  set :dirs do
9
17
  ['lib']
@@ -19,13 +27,26 @@ Alki do
19
27
  end
20
28
  end
21
29
 
30
+ reference_overlay '%main_loop', :reloadable_reference
31
+
32
+ factory :reloadable_reference do
33
+ require 'alki/reload/reloadable_delegator'
34
+ -> (ref) {
35
+ if main_loops
36
+ Alki::Reload::ReloadableDelegator.new(root.assembly_instance,ref)
37
+ else
38
+ ref.call
39
+ end
40
+ }
41
+ end
42
+
22
43
  service :handlers do
23
- [dsl_handler,load_path_handler]
44
+ [loader_handler,load_path_handler]
24
45
  end
25
46
 
26
- service :dsl_handler do
27
- require 'alki/reload/dsl_handler'
28
- Alki::Reload::DslHandler.new root_dir
47
+ service :loader_handler do
48
+ require 'alki/reload/loader_handler'
49
+ Alki::Reload::LoaderHandler.new root_dir
29
50
  end
30
51
 
31
52
  service :load_path_handler do
@@ -10,7 +10,7 @@ module Alki
10
10
  def handle_path(path)
11
11
  @dirs.each do |dir|
12
12
  if path.start_with? dir
13
- return path[dir.size..-1].match(%r{(?:(.*)/)?(.*).rb})[1..2]
13
+ return path[dir.size..-1].chomp('.rb')
14
14
  end
15
15
  end
16
16
  nil
@@ -1,8 +1,8 @@
1
- require 'alki/dsl/registry'
1
+ require 'alki/loader'
2
2
 
3
3
  module Alki
4
4
  module Reload
5
- class DslHandler
5
+ class LoaderHandler
6
6
  def initialize(root_dir)
7
7
  @root_dir = File.join(root_dir,'')
8
8
  end
@@ -11,17 +11,15 @@ module Alki
11
11
  dirs.each do |dir|
12
12
  dir = File.join(dir,'')
13
13
  if path.start_with? dir
14
- entry = Alki::Dsl::Registry.lookup(path)
15
- if entry && entry.data[:prefix] && entry.data[:name]
16
- return [entry.data[:prefix], entry.data[:name]]
17
- end
14
+ name = Alki::Loader.lookup_name path
15
+ return name if name
18
16
  end
19
17
  end
20
18
  nil
21
19
  end
22
20
 
23
21
  def dirs
24
- Alki::Dsl::Registry.registered_dirs.select do |d|
22
+ Alki::Loader.registered_paths.select do |d|
25
23
  d.start_with?(@root_dir)
26
24
  end
27
25
  end
@@ -0,0 +1,30 @@
1
+ require 'delegate'
2
+
3
+ module Alki
4
+ module Reload
5
+ class ReloadableDelegator < Delegator
6
+ def initialize(instance,ref)
7
+ @instance = instance
8
+ @ref = ref
9
+ end
10
+
11
+ def __getobj__
12
+ if !@obj || @instance_version != @instance.__version__
13
+ @ref.executor = @instance.assembly_executor
14
+ @obj = @ref.call
15
+ @instance_version = @instance.__version__
16
+ end
17
+ @obj
18
+ end
19
+
20
+ def method_missing(method,*args,&blk)
21
+ ref_meth = :"__reference_#{method}__"
22
+ if respond_to?(ref_meth,true)
23
+ ReloadableDelegator.new @instance, super(ref_meth, *args, &blk)
24
+ else
25
+ super
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,4 @@
1
1
  require 'alki/support'
2
- require 'alki/dsl/registry'
3
2
 
4
3
  module Alki
5
4
  module Reload
@@ -16,8 +15,9 @@ module Alki
16
15
  if path.end_with?('.rb')
17
16
  result = @handlers.lazy.map{|h| h.handle_path path }.find{|r| r != nil}
18
17
  if result
19
- add_const consts, *result
20
- files << path
18
+ if add_const consts, result
19
+ files << path
20
+ end
21
21
  end
22
22
  end
23
23
  end
@@ -33,9 +33,15 @@ module Alki
33
33
 
34
34
  private
35
35
 
36
- def add_const(consts,parent,name)
37
- unless whitelisted? parent, name
38
- parent = parent ? Alki::Support.load_class(parent) : Object
36
+ def add_const(consts,name)
37
+ unless @whitelist.include? name
38
+ md = name.match(%r{(.*)/(.*)})
39
+ if md
40
+ parent = Alki::Support.constantize Alki::Support.classify md[1]
41
+ name = md[2]
42
+ else
43
+ parent = Object
44
+ end
39
45
  name = Alki::Support.classify(name).to_sym
40
46
  if parent && parent.is_a?(Module) && parent.const_defined?(name,false)
41
47
  consts << [parent,name]
@@ -43,10 +49,6 @@ module Alki
43
49
  end
44
50
  end
45
51
  end
46
-
47
- def whitelisted?(parent,name)
48
- @whitelist.include?(parent ? File.join(parent,name) : name)
49
- end
50
52
  end
51
53
  end
52
54
  end
@@ -1,5 +1,5 @@
1
1
  module Alki
2
2
  module Reload
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alki-reload
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Edlefsen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-20 00:00:00.000000000 Z
11
+ date: 2016-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -58,20 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.9'
62
- - - ">="
63
- - !ruby/object:Gem::Version
64
- version: 0.9.1
61
+ version: '0.10'
65
62
  type: :runtime
66
63
  prerelease: false
67
64
  version_requirements: !ruby/object:Gem::Requirement
68
65
  requirements:
69
66
  - - "~>"
70
67
  - !ruby/object:Gem::Version
71
- version: '0.9'
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- version: 0.9.1
68
+ version: '0.10'
75
69
  description:
76
70
  email:
77
71
  - matt.edlefsen@gmail.com
@@ -83,15 +77,16 @@ files:
83
77
  - CODE_OF_CONDUCT.md
84
78
  - Gemfile
85
79
  - LICENSE.txt
86
- - README.md
80
+ - README.adoc
87
81
  - Rakefile
88
82
  - alki-reload.gemspec
89
83
  - config/assembly.rb
90
84
  - lib/alki/reload.rb
91
85
  - lib/alki/reload/assembly_delegator.rb
92
- - lib/alki/reload/dsl_handler.rb
93
86
  - lib/alki/reload/listen_watcher.rb
94
87
  - lib/alki/reload/load_path_handler.rb
88
+ - lib/alki/reload/loader_handler.rb
89
+ - lib/alki/reload/reloadable_delegator.rb
95
90
  - lib/alki/reload/reloader.rb
96
91
  - lib/alki/reload/unloader.rb
97
92
  - lib/alki/reload/version.rb
data/README.md DELETED
@@ -1,41 +0,0 @@
1
- # Alki::Reload
2
-
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/alki/reload`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
6
-
7
- ## Installation
8
-
9
- Add this line to your application's Gemfile:
10
-
11
- ```ruby
12
- gem 'alki-reload'
13
- ```
14
-
15
- And then execute:
16
-
17
- $ bundle
18
-
19
- Or install it yourself as:
20
-
21
- $ gem install alki-reload
22
-
23
- ## Usage
24
-
25
- TODO: Write usage instructions here
26
-
27
- ## Development
28
-
29
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
-
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
-
33
- ## Contributing
34
-
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/alki-reload. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
-
37
-
38
- ## License
39
-
40
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
41
-