alki-reload 0.1.0 → 0.2.0

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