volt 0.6.5 → 0.7.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 +4 -4
- data/Readme.md +47 -40
- data/VERSION +1 -1
- data/app/volt/controllers/notices_controller.rb +3 -3
- data/app/volt/tasks/live_query/data_store.rb +2 -2
- data/app/volt/tasks/live_query/live_query.rb +20 -20
- data/app/volt/tasks/live_query/live_query_pool.rb +6 -6
- data/app/volt/tasks/live_query/query_tracker.rb +15 -15
- data/app/volt/tasks/query_tasks.rb +13 -13
- data/app/volt/tasks/store_tasks.rb +7 -7
- data/app/volt/views/notices/index.html +17 -18
- data/lib/volt/assets/test.rb +2 -2
- data/lib/volt/benchmark/benchmark.rb +25 -23
- data/lib/volt/cli/asset_compile.rb +11 -0
- data/lib/volt/cli/new_gem.rb +16 -16
- data/lib/volt/cli.rb +14 -12
- data/lib/volt/console.rb +5 -6
- data/lib/volt/controllers/model_controller.rb +18 -18
- data/lib/volt/extra_core/array.rb +4 -4
- data/lib/volt/extra_core/hash.rb +3 -3
- data/lib/volt/extra_core/object.rb +6 -6
- data/lib/volt/extra_core/string.rb +6 -6
- data/lib/volt/extra_core/symbol.rb +5 -5
- data/lib/volt/extra_core/time.rb +4 -4
- data/lib/volt/extra_core/true_false.rb +6 -6
- data/lib/volt/extra_core/try.rb +9 -9
- data/lib/volt/models/array_model.rb +26 -26
- data/lib/volt/models/model.rb +35 -35
- data/lib/volt/models/model_hash_behaviour.rb +15 -15
- data/lib/volt/models/model_helpers.rb +8 -8
- data/lib/volt/models/model_wrapper.rb +6 -6
- data/lib/volt/models/persistors/array_store.rb +36 -36
- data/lib/volt/models/persistors/base.rb +6 -6
- data/lib/volt/models/persistors/flash.rb +5 -5
- data/lib/volt/models/persistors/model_identity_map.rb +2 -2
- data/lib/volt/models/persistors/model_store.rb +22 -22
- data/lib/volt/models/persistors/params.rb +3 -3
- data/lib/volt/models/persistors/query/query_listener.rb +14 -14
- data/lib/volt/models/persistors/query/query_listener_pool.rb +2 -2
- data/lib/volt/models/persistors/store.rb +8 -8
- data/lib/volt/models/persistors/store_factory.rb +2 -2
- data/lib/volt/models/url.rb +37 -37
- data/lib/volt/page/bindings/attribute_binding.rb +14 -14
- data/lib/volt/page/bindings/base_binding.rb +9 -9
- data/lib/volt/page/bindings/component_binding.rb +7 -7
- data/lib/volt/page/bindings/content_binding.rb +3 -3
- data/lib/volt/page/bindings/each_binding.rb +13 -13
- data/lib/volt/page/bindings/event_binding.rb +4 -4
- data/lib/volt/page/bindings/if_binding.rb +12 -12
- data/lib/volt/page/bindings/template_binding.rb +30 -30
- data/lib/volt/page/channel.rb +19 -19
- data/lib/volt/page/channel_stub.rb +6 -6
- data/lib/volt/page/document.rb +2 -2
- data/lib/volt/page/document_events.rb +4 -4
- data/lib/volt/page/draw_cycle.rb +3 -3
- data/lib/volt/page/memory_test.rb +6 -6
- data/lib/volt/page/page.rb +19 -19
- data/lib/volt/page/reactive_template.rb +9 -9
- data/lib/volt/page/sub_context.rb +5 -5
- data/lib/volt/page/targets/attribute_section.rb +9 -9
- data/lib/volt/page/targets/attribute_target.rb +3 -3
- data/lib/volt/page/targets/base_section.rb +2 -2
- data/lib/volt/page/targets/binding_document/component_node.rb +23 -23
- data/lib/volt/page/targets/binding_document/html_node.rb +2 -2
- data/lib/volt/page/targets/dom_section.rb +40 -38
- data/lib/volt/page/targets/dom_target.rb +2 -2
- data/lib/volt/page/tasks.rb +12 -12
- data/lib/volt/page/template_renderer.rb +4 -4
- data/lib/volt/page/url_tracker.rb +6 -6
- data/lib/volt/reactive/array_extensions.rb +2 -2
- data/lib/volt/reactive/destructive_methods.rb +5 -5
- data/lib/volt/reactive/event_chain.rb +25 -25
- data/lib/volt/reactive/events.rb +33 -33
- data/lib/volt/reactive/object_tracker.rb +21 -21
- data/lib/volt/reactive/object_tracking.rb +2 -2
- data/lib/volt/reactive/reactive_array.rb +57 -57
- data/lib/volt/reactive/reactive_tags.rb +16 -16
- data/lib/volt/reactive/reactive_value.rb +72 -72
- data/lib/volt/reactive/string_extensions.rb +3 -3
- data/lib/volt/router/routes.rb +22 -23
- data/lib/volt/server/component_handler.rb +5 -5
- data/lib/volt/server/component_templates.rb +14 -11
- data/lib/volt/server/html_parser/attribute_scope.rb +116 -0
- data/lib/volt/server/html_parser/each_scope.rb +18 -0
- data/lib/volt/server/html_parser/if_view_scope.rb +71 -0
- data/lib/volt/server/html_parser/sandlebars_parser.rb +219 -0
- data/lib/volt/server/html_parser/textarea_scope.rb +31 -0
- data/lib/volt/server/html_parser/view_handler.rb +82 -0
- data/lib/volt/server/html_parser/view_parser.rb +23 -0
- data/lib/volt/server/html_parser/view_scope.rb +145 -0
- data/lib/volt/server/rack/asset_files.rb +17 -17
- data/lib/volt/server/rack/component_paths.rb +18 -18
- data/lib/volt/server/rack/index_files.rb +8 -8
- data/lib/volt/server/rack/opal_files.rb +11 -11
- data/lib/volt/server/socket_connection_handler.rb +13 -13
- data/lib/volt/server/socket_connection_handler_stub.rb +2 -2
- data/lib/volt/server.rb +18 -18
- data/lib/volt/tasks/dispatcher.rb +5 -5
- data/lib/volt/utils/ejson.rb +2 -2
- data/lib/volt/utils/generic_counting_pool.rb +8 -8
- data/lib/volt/utils/generic_pool.rb +16 -16
- data/lib/volt/volt/environment.rb +4 -4
- data/lib/volt.rb +6 -6
- data/spec/integration/test_integration_spec.rb +2 -2
- data/spec/models/event_chain_spec.rb +38 -38
- data/spec/models/model_spec.rb +128 -128
- data/spec/models/old_model_spec.rb +17 -17
- data/spec/models/persistors/params_spec.rb +3 -3
- data/spec/models/persistors/store_spec.rb +7 -7
- data/spec/models/reactive_array_spec.rb +82 -82
- data/spec/models/reactive_generator_spec.rb +11 -11
- data/spec/models/reactive_tags_spec.rb +6 -6
- data/spec/models/reactive_value_spec.rb +70 -70
- data/spec/models/store_spec.rb +4 -4
- data/spec/models/string_extensions_spec.rb +13 -13
- data/spec/page/bindings/content_binding_spec.rb +6 -6
- data/spec/page/sub_context_spec.rb +1 -1
- data/spec/router/routes_spec.rb +3 -3
- data/spec/server/html_parser/sample_page.html +595 -0
- data/spec/server/html_parser/sandlebars_parser_spec.rb +192 -0
- data/spec/server/html_parser/view_parser_spec.rb +286 -0
- data/spec/server/rack/asset_files_spec.rb +6 -6
- data/spec/server/rack/component_paths_spec.rb +5 -5
- data/spec/spec_helper.rb +4 -5
- data/spec/store/mongo_spec.rb +3 -3
- data/spec/tasks/live_query_spec.rb +6 -6
- data/spec/tasks/query_tasks.rb +4 -4
- data/spec/tasks/query_tracker_spec.rb +20 -20
- data/spec/templates/targets/binding_document/component_node_spec.rb +4 -4
- data/spec/templates/template_binding_spec.rb +28 -28
- data/spec/utils/generic_counting_pool_spec.rb +5 -5
- data/spec/utils/generic_pool_spec.rb +14 -14
- data/templates/newgem/app/newgem/views/index/index.html +1 -2
- data/templates/project/app/home/config/dependencies.rb +1 -1
- data/templates/project/app/home/controllers/index_controller.rb +1 -1
- data/templates/project/app/home/views/index/about.html +4 -6
- data/templates/project/app/home/views/index/home.html +4 -5
- data/templates/project/app/home/views/index/index.html +8 -9
- data/templates/project/spec/spec_helper.rb +1 -1
- metadata +17 -8
- data/lib/volt/server/binding_setup.rb +0 -2
- data/lib/volt/server/if_binding_setup.rb +0 -31
- data/lib/volt/server/scope.rb +0 -43
- data/lib/volt/server/template_parser.rb +0 -453
- data/spec/server/template_parser_spec.rb +0 -50
|
@@ -5,25 +5,25 @@ class AssetFiles
|
|
|
5
5
|
@assets = []
|
|
6
6
|
@included_components = {}
|
|
7
7
|
@components = []
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
component('volt')
|
|
10
10
|
component(component_name)
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
def load_dependencies(path)
|
|
14
14
|
if path
|
|
15
15
|
dependencies_file = File.join(path, "config/dependencies.rb")
|
|
16
16
|
else
|
|
17
17
|
raise "Unable to find component #{component_name.inspect}"
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
if File.exists?(dependencies_file)
|
|
21
21
|
# Run the dependencies file in this asset files context
|
|
22
22
|
code = File.read(dependencies_file)
|
|
23
23
|
instance_eval(code)
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
def component(name)
|
|
28
28
|
unless @included_components[name]
|
|
29
29
|
# Get the path to the component
|
|
@@ -34,17 +34,17 @@ class AssetFiles
|
|
|
34
34
|
|
|
35
35
|
# Load the dependencies
|
|
36
36
|
load_dependencies(path)
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
# Add any assets
|
|
39
39
|
add_assets(path)
|
|
40
40
|
@components << [path, name]
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
def components
|
|
45
45
|
@included_components.keys
|
|
46
46
|
end
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
def javascript_file(url)
|
|
49
49
|
@assets << [:javascript_file, url]
|
|
50
50
|
end
|
|
@@ -52,19 +52,19 @@ class AssetFiles
|
|
|
52
52
|
def css_file(url)
|
|
53
53
|
@assets << [:css_file, url]
|
|
54
54
|
end
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
def component_paths
|
|
57
57
|
return @components
|
|
58
58
|
end
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
def add_assets(path)
|
|
61
61
|
asset_folder = File.join(path, 'assets')
|
|
62
62
|
if File.directory?(asset_folder)
|
|
63
63
|
@assets << [:folder, asset_folder]
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
|
|
67
|
+
|
|
68
68
|
def javascript_files(opal_files)
|
|
69
69
|
javascript_files = []
|
|
70
70
|
@assets.each do |type, path|
|
|
@@ -75,7 +75,7 @@ class AssetFiles
|
|
|
75
75
|
javascript_files << path
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
opal_js_files = []
|
|
80
80
|
if Volt.source_maps?
|
|
81
81
|
opal_js_files += opal_files.environment['volt/page/page'].to_a.map {|v| '/assets/' + v.logical_path + '?body=1' }
|
|
@@ -85,10 +85,10 @@ class AssetFiles
|
|
|
85
85
|
opal_js_files << '/components/home.js'
|
|
86
86
|
|
|
87
87
|
javascript_files += opal_js_files
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
return javascript_files
|
|
90
90
|
end
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
def css_files
|
|
93
93
|
css_files = []
|
|
94
94
|
@assets.each do |type, path|
|
|
@@ -99,8 +99,8 @@ class AssetFiles
|
|
|
99
99
|
css_files << path
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
return css_files
|
|
104
104
|
end
|
|
105
|
-
|
|
106
|
-
end
|
|
105
|
+
|
|
106
|
+
end
|
|
@@ -3,62 +3,62 @@ class ComponentPaths
|
|
|
3
3
|
def initialize(root=nil)
|
|
4
4
|
@root = root || Dir.pwd
|
|
5
5
|
end
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
# Yield for every folder where we might find components
|
|
8
8
|
def app_folders
|
|
9
9
|
# Find all app folders
|
|
10
10
|
@app_folders ||= begin
|
|
11
11
|
app_folders = ["#{@root}/app", "#{@root}/vendor/app"].map {|f| File.expand_path(f) }
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
# Gem folders with volt in them
|
|
14
14
|
# TODO: we should probably qualify this a bit more
|
|
15
15
|
app_folders += Gem.loaded_specs.values.map { |g| g.full_gem_path }.reject {|g| g !~ /volt/ }.map {|f| f + '/app' }
|
|
16
16
|
|
|
17
17
|
app_folders
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
# Yield each app folder and return a flattened array with
|
|
21
21
|
# the results
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
files = []
|
|
24
24
|
@app_folders.each do |app_folder|
|
|
25
25
|
files << yield(app_folder)
|
|
26
26
|
end
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
return files.flatten
|
|
29
29
|
end
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
# returns an array of every folder that is a component
|
|
32
32
|
def components
|
|
33
33
|
return @components if @components
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
@components = {}
|
|
36
36
|
app_folders do |app_folder|
|
|
37
37
|
Dir["#{app_folder}/*"].sort.each do |folder|
|
|
38
38
|
if File.directory?(folder)
|
|
39
39
|
folder_name = folder[/[^\/]+$/]
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
@components[folder_name] ||= []
|
|
42
|
-
@components[folder_name] << folder
|
|
42
|
+
@components[folder_name] << folder
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
return @components
|
|
48
48
|
end
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
# Makes each components classes available on the load path, require classes.
|
|
51
51
|
def require_in_components
|
|
52
52
|
# app_folders do |app_folder|
|
|
53
53
|
# $LOAD_PATH.unshift(app_folder)
|
|
54
|
-
#
|
|
54
|
+
#
|
|
55
55
|
# Dir["#{app_folder}/*/{controllers,model}/*.rb"].each do |ruby_file|
|
|
56
56
|
# path = ruby_file.gsub(/^#{app_folder}\//, '')[0..-4]
|
|
57
57
|
# puts "Path: #{path}"
|
|
58
58
|
# # require(path)
|
|
59
59
|
# end
|
|
60
60
|
# end
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
# add each tasks folder directly
|
|
63
63
|
components.each do |name,component_folders|
|
|
64
64
|
component_folders.each do |component_folder|
|
|
@@ -68,18 +68,18 @@ class ComponentPaths
|
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
# Returns the path for a specific component
|
|
73
73
|
def component_path(name)
|
|
74
74
|
folders = components[name]
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
if folders
|
|
77
77
|
return folders.first
|
|
78
78
|
else
|
|
79
79
|
return nil
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
# Return every asset folder we need to serve from
|
|
84
84
|
def asset_folders
|
|
85
85
|
folders = []
|
|
@@ -88,8 +88,8 @@ class ComponentPaths
|
|
|
88
88
|
folders << yield(asset_folder)
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
folders.flatten
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
end
|
|
95
|
+
end
|
|
@@ -7,7 +7,7 @@ class IndexFiles
|
|
|
7
7
|
@app = app
|
|
8
8
|
@component_paths = component_paths
|
|
9
9
|
@opal_files = opal_files
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
@@router ||= Routes.new.define do
|
|
12
12
|
# Find the route file
|
|
13
13
|
home_path = component_paths.component_path('home')
|
|
@@ -15,12 +15,12 @@ class IndexFiles
|
|
|
15
15
|
eval(route_file)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
def route_match?(path)
|
|
20
20
|
@@router.path_matchers.each do |path_matcher|
|
|
21
21
|
return true if path =~ path_matcher
|
|
22
22
|
end
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
return false
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -31,24 +31,24 @@ class IndexFiles
|
|
|
31
31
|
@app.call env
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
def html
|
|
36
36
|
index_path = File.expand_path(File.join(Volt.root, "public/index.html"))
|
|
37
37
|
html = File.read(index_path)
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
ERB.new(html).result(binding)
|
|
40
40
|
end
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
def javascript_files
|
|
43
43
|
# TODO: Cache somehow, this is being loaded every time
|
|
44
44
|
AssetFiles.new('home', @component_paths).javascript_files(@opal_files)
|
|
45
45
|
end
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
def css_files
|
|
48
48
|
AssetFiles.new('home', @component_paths).css_files
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
|
|
53
53
|
end
|
|
54
54
|
|
|
@@ -7,31 +7,31 @@ end
|
|
|
7
7
|
# Sets up the maps for the opal assets, and source maps if enabled.
|
|
8
8
|
class OpalFiles
|
|
9
9
|
attr_reader :environment
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
def initialize(builder, app_path, component_paths)
|
|
12
12
|
Opal::Processor.source_map_enabled = Volt.source_maps?
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
# Don't run arity checks in production
|
|
15
15
|
# Opal::Processor.arity_check_enabled = !Volt.env.production?
|
|
16
16
|
# Opal::Processor.dynamic_require_severity = :raise
|
|
17
17
|
|
|
18
18
|
@component_paths = component_paths
|
|
19
19
|
@environment = Opal::Environment.new
|
|
20
|
-
|
|
21
|
-
# Since the scope changes in builder blocks, we need to capture
|
|
20
|
+
|
|
21
|
+
# Since the scope changes in builder blocks, we need to capture
|
|
22
22
|
# environment in closure
|
|
23
23
|
environment = @environment
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
environment.cache = Sprockets::Cache::FileStore.new("./tmp")
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
if Volt.env.production?
|
|
28
28
|
# Compress in production
|
|
29
29
|
environment.js_compressor = Sprockets::UglifierCompressor
|
|
30
30
|
environment.css_compressor = Sprockets::YUICompressor
|
|
31
31
|
end
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
environment.append_path(app_path)
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
volt_gem_lib_path = File.expand_path(File.join(File.dirname(__FILE__), "../../.."))
|
|
36
36
|
environment.append_path(volt_gem_lib_path)
|
|
37
37
|
|
|
@@ -58,11 +58,11 @@ class OpalFiles
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
def add_asset_folders(environment)
|
|
63
63
|
@component_paths.asset_folders do |asset_folder|
|
|
64
64
|
environment.append_path(asset_folder)
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
|
-
|
|
68
|
-
end
|
|
67
|
+
|
|
68
|
+
end
|
|
@@ -3,15 +3,15 @@ require 'sockjs/session'
|
|
|
3
3
|
|
|
4
4
|
class SocketConnectionHandler < SockJS::Session
|
|
5
5
|
# Create one instance of the dispatcher
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def self.dispatcher=(val)
|
|
8
8
|
@@dispatcher = val
|
|
9
9
|
end
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
def self.dispatcher
|
|
12
12
|
@@dispatcher
|
|
13
13
|
end
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
# Sends a message to all, optionally skipping a users channel
|
|
16
16
|
def self.send_message_all(skip_channel=nil, *args)
|
|
17
17
|
@@channels.each do |channel|
|
|
@@ -20,32 +20,32 @@ class SocketConnectionHandler < SockJS::Session
|
|
|
20
20
|
end
|
|
21
21
|
channel.send_message(*args)
|
|
22
22
|
end
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
end
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
def initialize(session, *args)
|
|
27
27
|
@session = session
|
|
28
28
|
|
|
29
29
|
@@channels ||= []
|
|
30
30
|
@@channels << self
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
super
|
|
33
33
|
end
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
def process_message(message)
|
|
36
36
|
# self.class.message_all(message)
|
|
37
37
|
# Messages are json and wrapped in an array
|
|
38
38
|
message = JSON.parse(message).first
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
@@dispatcher.dispatch(self, message)
|
|
41
41
|
end
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
def send_message(*args)
|
|
44
44
|
str = JSON.dump([*args])
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
send(str)
|
|
47
47
|
end
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
def closed
|
|
50
50
|
puts "CHANNEL CLOSED: #{self.inspect}"
|
|
51
51
|
# Remove ourself from the available channels
|
|
@@ -53,9 +53,9 @@ class SocketConnectionHandler < SockJS::Session
|
|
|
53
53
|
|
|
54
54
|
QueryTasks.new(self).close!
|
|
55
55
|
end
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
def inspect
|
|
58
58
|
"<#{self.class.to_s}:#{object_id}>"
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
end
|
|
61
|
+
end
|
|
@@ -6,7 +6,7 @@ class SocketConnectionHandlerStub
|
|
|
6
6
|
def self.dispatcher
|
|
7
7
|
@@dispatcher
|
|
8
8
|
end
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
def initialize(channel_stub)
|
|
11
11
|
@channel_stub = channel_stub
|
|
12
12
|
end
|
|
@@ -23,4 +23,4 @@ class SocketConnectionHandlerStub
|
|
|
23
23
|
def send_message(*args)
|
|
24
24
|
@channel_stub.message_received(*args)
|
|
25
25
|
end
|
|
26
|
-
end
|
|
26
|
+
end
|
data/lib/volt/server.rb
CHANGED
|
@@ -23,20 +23,20 @@ require 'volt/tasks/dispatcher'
|
|
|
23
23
|
|
|
24
24
|
module Rack
|
|
25
25
|
# TODO: For some reason in Rack (or maybe thin), 304 headers close
|
|
26
|
-
# the http connection. We might need to make this check if keep
|
|
26
|
+
# the http connection. We might need to make this check if keep
|
|
27
27
|
# alive was in the request.
|
|
28
28
|
class KeepAlive
|
|
29
29
|
def initialize(app)
|
|
30
30
|
@app = app
|
|
31
31
|
end
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
def call(env)
|
|
34
34
|
status, headers, body = @app.call(env)
|
|
35
35
|
|
|
36
36
|
if status == 304 && env['HTTP_CONNECTION'].downcase == 'keep-alive'
|
|
37
37
|
headers['Connection'] = 'keep-alive'
|
|
38
38
|
end
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
[status, headers, body]
|
|
41
41
|
end
|
|
42
42
|
end
|
|
@@ -48,18 +48,18 @@ class Server
|
|
|
48
48
|
Volt.root = root_path
|
|
49
49
|
|
|
50
50
|
@app_path = File.expand_path(File.join(root_path, "app"))
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
@component_paths = ComponentPaths.new(root_path)
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
setup_change_listener
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
display_welcome
|
|
57
57
|
end
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
def display_welcome
|
|
60
|
-
puts File.read(File.join(File.dirname(__FILE__), "server/banner.txt"))
|
|
60
|
+
puts File.read(File.join(File.dirname(__FILE__), "server/banner.txt"))
|
|
61
61
|
end
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
def setup_change_listener
|
|
64
64
|
# Setup the listeners for file changes
|
|
65
65
|
listener = Listen.to("#{@app_path}/") do |modified, added, removed|
|
|
@@ -67,10 +67,10 @@ class Server
|
|
|
67
67
|
end
|
|
68
68
|
listener.start
|
|
69
69
|
end
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
def app
|
|
72
72
|
@app = Rack::Builder.new
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
# Should only be used in production
|
|
75
75
|
# @app.use Rack::Deflater
|
|
76
76
|
|
|
@@ -80,7 +80,7 @@ class Server
|
|
|
80
80
|
@app.use Rack::KeepAlive
|
|
81
81
|
@app.use Rack::ConditionalGet
|
|
82
82
|
@app.use Rack::ETag
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
@app.use Rack::CommonLogger
|
|
85
85
|
@app.use Rack::ShowExceptions
|
|
86
86
|
|
|
@@ -88,24 +88,24 @@ class Server
|
|
|
88
88
|
@app.map '/components' do
|
|
89
89
|
run ComponentHandler.new(component_paths)
|
|
90
90
|
end
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
# Serve the opal files
|
|
93
93
|
opal_files = OpalFiles.new(@app, @app_path, @component_paths)
|
|
94
94
|
|
|
95
95
|
# Serve the main html files from public, also figure out
|
|
96
96
|
# which JS/CSS files to serve.
|
|
97
97
|
@app.use IndexFiles, @component_paths, opal_files
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
# Handle socks js connection
|
|
100
100
|
if RUBY_PLATFORM != 'java'
|
|
101
101
|
component_paths.require_in_components
|
|
102
102
|
SocketConnectionHandler.dispatcher = Dispatcher.new
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
@app.map "/channel" do
|
|
105
105
|
run Rack::SockJS.new(SocketConnectionHandler)#, :websocket => false
|
|
106
106
|
end
|
|
107
107
|
end
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
@app.use Rack::Static,
|
|
110
110
|
:urls => ["/"],
|
|
111
111
|
:root => "public",
|
|
@@ -115,7 +115,7 @@ class Server
|
|
|
115
115
|
]
|
|
116
116
|
|
|
117
117
|
@app.run lambda{ |env| [ 404, { 'Content-Type' => 'text/html' }, ['404 - page not found'] ] }
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
return @app
|
|
120
120
|
end
|
|
121
|
-
end
|
|
121
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# The task dispatcher is responsible for taking incoming messages
|
|
2
2
|
# from the socket channel and dispatching them to the proper handler.
|
|
3
3
|
class Dispatcher
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
def dispatch(channel, message)
|
|
6
6
|
callback_id, class_name, method_name, *args = message
|
|
7
7
|
|
|
@@ -9,10 +9,10 @@ class Dispatcher
|
|
|
9
9
|
if class_name[/Tasks$/] && !class_name['::']
|
|
10
10
|
# TODO: Improve error on a class we don't have
|
|
11
11
|
require(class_name.underscore)
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
# Get the class
|
|
14
14
|
klass = Object.send(:const_get, class_name)
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
# Init and send the method
|
|
17
17
|
begin
|
|
18
18
|
result = klass.new(channel, self).send(method_name, *args)
|
|
@@ -24,11 +24,11 @@ class Dispatcher
|
|
|
24
24
|
result = nil
|
|
25
25
|
error = e
|
|
26
26
|
end
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
if callback_id
|
|
29
29
|
# Callback with result
|
|
30
30
|
channel.send_message('response', callback_id, result, error)
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
|
-
end
|
|
34
|
+
end
|
data/lib/volt/utils/ejson.rb
CHANGED
|
@@ -2,7 +2,7 @@ require 'volt/utils/generic_pool'
|
|
|
2
2
|
|
|
3
3
|
# A counting pool behaves like a normal GenericPool, except for
|
|
4
4
|
# each time lookup is called, remove should be called when complete.
|
|
5
|
-
# The item will be completely removed from the GenericCountingPool
|
|
5
|
+
# The item will be completely removed from the GenericCountingPool
|
|
6
6
|
# only when it has been removed an equal number of times it has been
|
|
7
7
|
# looked up.
|
|
8
8
|
class GenericCountingPool < GenericPool
|
|
@@ -10,32 +10,32 @@ class GenericCountingPool < GenericPool
|
|
|
10
10
|
def generate_new(*args)
|
|
11
11
|
[0, create(*args)]
|
|
12
12
|
end
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
# Finds an item and tracks that it was checked out. Use
|
|
15
15
|
# #remove when the item is no longer needed.
|
|
16
16
|
def find(*args, &block)
|
|
17
17
|
item = __lookup(*args, &block)
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
item[0] += 1
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
return item[1]
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
# Lookups an item
|
|
25
25
|
def lookup(*args, &block)
|
|
26
26
|
item = super(*args, &block)
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
return item[1]
|
|
29
29
|
end
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
def transform_item(item)
|
|
32
32
|
[0, item]
|
|
33
33
|
end
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
def remove(*args)
|
|
36
36
|
item = __lookup(*args)
|
|
37
37
|
item[0] -= 1
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
if item[0] == 0
|
|
40
40
|
# Last one using this item has removed it.
|
|
41
41
|
super(*args)
|
|
@@ -13,19 +13,19 @@ class GenericPool
|
|
|
13
13
|
def initialize
|
|
14
14
|
@pool = {}
|
|
15
15
|
end
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
def lookup(*args, &block)
|
|
18
18
|
section = @pool
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
# TODO: This is to work around opal issue #500
|
|
21
21
|
if RUBY_PLATFORM == 'opal'
|
|
22
22
|
args.pop if args.last == nil
|
|
23
23
|
end
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
|
|
25
|
+
|
|
26
26
|
args.each_with_index do |arg, index|
|
|
27
27
|
last = (args.size-1) == index
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
if last
|
|
30
30
|
# return, creating if needed
|
|
31
31
|
return(section[arg] ||= create_new_item(*args, &block))
|
|
@@ -36,7 +36,7 @@ class GenericPool
|
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
# Does the actual creating, if a block is not passed in, it calls
|
|
41
41
|
# #create on the class.
|
|
42
42
|
def create_new_item(*args)
|
|
@@ -45,28 +45,28 @@ class GenericPool
|
|
|
45
45
|
else
|
|
46
46
|
new_item = create(*args)
|
|
47
47
|
end
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
return transform_item(new_item)
|
|
50
50
|
end
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
# Allow other pools to override how the created item gets stored.
|
|
53
53
|
def transform_item(item)
|
|
54
54
|
item
|
|
55
55
|
end
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
# Make sure we call the pool one from lookup_all and not
|
|
58
58
|
# an overridden one.
|
|
59
59
|
alias_method :__lookup, :lookup
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
def lookup_all(*args)
|
|
62
62
|
__lookup(*args).values
|
|
63
63
|
end
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
def remove(*args)
|
|
66
66
|
stack = []
|
|
67
67
|
section = @pool
|
|
68
|
-
|
|
69
|
-
args.each_with_index do |arg, index|
|
|
68
|
+
|
|
69
|
+
args.each_with_index do |arg, index|
|
|
70
70
|
stack << section
|
|
71
71
|
|
|
72
72
|
if args.size-1 == index
|
|
@@ -75,14 +75,14 @@ class GenericPool
|
|
|
75
75
|
section = section[arg]
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
(stack.size-1).downto(1) do |index|
|
|
80
80
|
node = stack[index]
|
|
81
81
|
parent = stack[index-1]
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
if node.size == 0
|
|
84
84
|
parent.delete(args[index-1])
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
|
-
end
|
|
88
|
+
end
|