volt 0.9.5.pre4 → 0.9.5.pre5
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/CHANGELOG.md +10 -0
- data/README.md +13 -5
- data/app/volt/assets/css/{notices.css.scss → notices.scss} +0 -0
- data/app/volt/models/active_volt_instance.rb +1 -1
- data/app/volt/tasks/live_query/live_query.rb +11 -3
- data/app/volt/tasks/store_tasks.rb +14 -17
- data/lib/volt/cli.rb +22 -0
- data/lib/volt/cli/asset_compile.rb +63 -63
- data/lib/volt/cli/base_index_renderer.rb +26 -0
- data/lib/volt/cli/generate.rb +1 -1
- data/lib/volt/config.rb +1 -0
- data/lib/volt/controllers/model_controller.rb +37 -1
- data/lib/volt/extra_core/array.rb +22 -0
- data/lib/volt/models/array_model.rb +7 -1
- data/lib/volt/models/errors.rb +1 -1
- data/lib/volt/models/field_helpers.rb +36 -21
- data/lib/volt/models/model.rb +16 -0
- data/lib/volt/models/validations/validations.rb +21 -6
- data/lib/volt/models/validators/type_validator.rb +35 -3
- data/lib/volt/page/bindings/content_binding.rb +1 -1
- data/lib/volt/page/bindings/event_binding.rb +40 -16
- data/lib/volt/page/document_events.rb +8 -6
- data/lib/volt/reactive/reactive_array.rb +18 -1
- data/lib/volt/server/forking_server.rb +7 -1
- data/lib/volt/server/html_parser/attribute_scope.rb +26 -0
- data/lib/volt/server/html_parser/component_view_scope.rb +30 -22
- data/lib/volt/server/middleware/default_middleware_stack.rb +6 -1
- data/lib/volt/server/rack/asset_files.rb +5 -3
- data/lib/volt/server/rack/opal_files.rb +35 -23
- data/lib/volt/server/rack/sprockets_helpers_setup.rb +71 -0
- data/lib/volt/server/template_handlers/view_processor.rb +1 -2
- data/lib/volt/utils/promise_extensions.rb +1 -1
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +0 -2
- data/lib/volt/volt/client_setup/browser.rb +11 -0
- data/spec/apps/kitchen_sink/Gemfile +37 -14
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +3 -0
- data/spec/apps/kitchen_sink/app/main/controllers/events_controller.rb +26 -0
- data/spec/apps/kitchen_sink/app/main/views/events/index.html +30 -0
- data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +3 -0
- data/spec/apps/kitchen_sink/app/main/views/main/yield.html +1 -6
- data/spec/apps/kitchen_sink/app/main/views/{yield-component → yield_component}/index.html +0 -0
- data/spec/extra_core/array_spec.rb +26 -0
- data/spec/integration/bindings_spec.rb +9 -0
- data/spec/integration/event_spec.rb +19 -0
- data/spec/models/array_model_spec.rb +13 -0
- data/spec/models/field_helpers_spec.rb +2 -2
- data/spec/models/validations_spec.rb +31 -0
- data/spec/models/validators/type_validator_spec.rb +47 -1
- data/spec/reactive/reactive_array_spec.rb +46 -0
- data/spec/server/forking_server_spec.rb +27 -0
- data/spec/server/html_parser/view_scope_spec.rb +44 -0
- data/spec/server/rack/asset_files_spec.rb +2 -2
- data/templates/project/Gemfile.tt +8 -0
- data/templates/project/config/app.rb.tt +2 -1
- data/volt.gemspec +1 -1
- metadata +31 -5
@@ -1,6 +1,30 @@
|
|
1
1
|
module Volt
|
2
2
|
# Included into ViewScope to provide processing for attributes
|
3
3
|
module AttributeScope
|
4
|
+
module ClassMethods
|
5
|
+
def methodize_string(str)
|
6
|
+
# Convert the string passed in to the binding so it returns a ruby Method
|
7
|
+
# instance
|
8
|
+
parts = str.split('.')
|
9
|
+
|
10
|
+
end_call = parts.last.strip
|
11
|
+
|
12
|
+
# If no method(args) is passed, we assume they want to convert the method
|
13
|
+
# to a Method, to be called with *args (from any trigger's), then event.
|
14
|
+
if str !~ /[\[\]\$\@\=]/ && end_call =~ /[_a-z0-9!?]+$/
|
15
|
+
parts[-1] = "method(:#{end_call})"
|
16
|
+
|
17
|
+
str = parts.join('.')
|
18
|
+
end
|
19
|
+
|
20
|
+
str
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.included(base)
|
25
|
+
base.send :extend, ClassMethods
|
26
|
+
end
|
27
|
+
|
4
28
|
# Take the attributes and create any bindings
|
5
29
|
def process_attributes(tag_name, attributes)
|
6
30
|
new_attributes = attributes.dup
|
@@ -29,6 +53,8 @@ module Volt
|
|
29
53
|
# Remove the e- attribute
|
30
54
|
attributes.delete(name)
|
31
55
|
|
56
|
+
value = self.class.methodize_string(value)
|
57
|
+
|
32
58
|
save_binding(id, "lambda { |__p, __t, __c, __id| Volt::EventBinding.new(__p, __t, __c, __id, #{event.inspect}, Proc.new {|event| #{value} })}")
|
33
59
|
end
|
34
60
|
|
@@ -7,38 +7,46 @@ module Volt
|
|
7
7
|
|
8
8
|
@binding_in_path = path
|
9
9
|
|
10
|
-
component_name = tag_name[1..-1].tr(':', '/')
|
10
|
+
component_name = tag_name[1..-1].tr('-', '_').tr(':', '/')
|
11
11
|
|
12
12
|
data_hash = []
|
13
13
|
attributes.each_pair do |name, value|
|
14
14
|
name = name.tr('-', '_')
|
15
|
-
parts, binding_count = binding_parts_and_count(value)
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
if name[0..1] == 'e_'
|
17
|
+
# Event binding
|
18
|
+
value = ViewScope.methodize_string(value.strip)
|
19
|
+
data_hash << "#{name.inspect} => Proc.new {|event| #{value} }"
|
20
|
+
else
|
21
|
+
parts, binding_count = binding_parts_and_count(value)
|
22
|
+
|
23
|
+
# if this attribute has bindings
|
24
|
+
if binding_count > 0
|
25
|
+
if binding_count > 1
|
26
|
+
# Multiple bindings
|
27
|
+
elsif parts.size == 1 && binding_count == 1
|
28
|
+
# A single binding
|
29
|
+
getter = value[2...-2].strip
|
25
30
|
|
26
|
-
|
27
|
-
data_hash << "#{(name + '=').inspect} => Proc.new { |val| #{setter} }"
|
31
|
+
data_hash << "#{name.inspect} => Proc.new { #{getter} }"
|
28
32
|
|
29
|
-
|
30
|
-
|
33
|
+
setter = getter_to_setter(getter)
|
34
|
+
data_hash << "#{(name + '=').inspect} => Proc.new { |val| #{setter} }"
|
31
35
|
|
32
|
-
|
33
|
-
|
34
|
-
data_hash << "#{(name + '_parent').inspect} => Proc.new { #{parent} }"
|
36
|
+
# Add an _parent fetcher. Useful for things like volt-fields to get the parent model.
|
37
|
+
parent = parent_fetcher(getter)
|
35
38
|
|
36
|
-
|
37
|
-
|
39
|
+
# TODO: This adds some overhead, perhaps there is a way to compute this dynamically on the
|
40
|
+
# front-end.
|
41
|
+
data_hash << "#{(name + '_parent').inspect} => Proc.new { #{parent} }"
|
42
|
+
|
43
|
+
# Add a _last_method property. This is useful
|
44
|
+
data_hash << "#{(name + '_last_method').inspect} => #{last_method_name(getter).inspect}"
|
45
|
+
end
|
46
|
+
else
|
47
|
+
# String
|
48
|
+
data_hash << "#{name.inspect} => #{value.inspect}"
|
38
49
|
end
|
39
|
-
else
|
40
|
-
# String
|
41
|
-
data_hash << "#{name.inspect} => #{value.inspect}"
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
@@ -6,6 +6,7 @@ require 'volt/server/rack/quiet_common_logger'
|
|
6
6
|
require 'volt/server/rack/opal_files'
|
7
7
|
require 'volt/server/rack/index_files'
|
8
8
|
require 'volt/server/rack/http_resource'
|
9
|
+
require 'volt/server/rack/sprockets_helpers_setup'
|
9
10
|
|
10
11
|
|
11
12
|
|
@@ -33,7 +34,9 @@ module Volt
|
|
33
34
|
}
|
34
35
|
|
35
36
|
rack_app.use QuietCommonLogger
|
36
|
-
|
37
|
+
if Volt.env.development? || Volt.env.test?
|
38
|
+
rack_app.use Rack::ShowExceptions
|
39
|
+
end
|
37
40
|
end
|
38
41
|
|
39
42
|
# Setup the middleware that we need to wait for components to boot before we
|
@@ -44,6 +47,8 @@ module Volt
|
|
44
47
|
volt_app.opal_files = opal_files
|
45
48
|
volt_app.sprockets = opal_files.environment
|
46
49
|
|
50
|
+
Volt::SprocketsHelpersSetup.new(volt_app.sprockets)
|
51
|
+
|
47
52
|
# Serve the main html files from public, also figure out
|
48
53
|
# which JS/CSS files to serve.
|
49
54
|
rack_app.use IndexFiles, volt_app, volt_app.component_paths, opal_files
|
@@ -172,7 +172,9 @@ module Volt
|
|
172
172
|
# aren't imported by default:
|
173
173
|
# http://sass-lang.com/guide
|
174
174
|
css_files += Dir["#{path}/**/[^_]*.{css,scss}"].sort.map do |folder|
|
175
|
-
'/assets' + folder[path.size..-1].gsub(/[.]scss$/, '')
|
175
|
+
css_path = '/assets' + folder[path.size..-1].gsub(/[.]scss$/, '')
|
176
|
+
css_path += '.css' unless css_path =~ /[.]css$/
|
177
|
+
css_path
|
176
178
|
end
|
177
179
|
when :css_file
|
178
180
|
css_files << path
|
@@ -185,10 +187,10 @@ module Volt
|
|
185
187
|
# #javascript is only used on the server
|
186
188
|
unless RUBY_PLATFORM == 'opal'
|
187
189
|
# Parses the javascript tags to reutrn the following:
|
188
|
-
# [[:
|
190
|
+
# [[:src, '/somefile.js'], [:body, 'var inlinejs = true;']]
|
189
191
|
def javascript(volt_app)
|
190
192
|
javascript_tags(volt_app)
|
191
|
-
.scan(/[<]script([^>]*)[>](.*?)[<]\/script[^>]*[>]/)
|
193
|
+
.scan(/[<]script([^>]*)[>](.*?)[<]\/script[^>]*[>]/m)
|
192
194
|
.map do |attrs, body|
|
193
195
|
src = attrs.match(/[\s|$]src\s*[=]\s*["']([^"']+?)["']/)
|
194
196
|
|
@@ -41,10 +41,6 @@ module Volt
|
|
41
41
|
# @environment = Opal::Environment.new
|
42
42
|
@environment = @server.sprockets
|
43
43
|
|
44
|
-
# Since the scope changes in builder blocks, we need to capture
|
45
|
-
# environment in closure
|
46
|
-
environment = @environment
|
47
|
-
|
48
44
|
environment.cache = Sprockets::Cache::FileStore.new('./tmp')
|
49
45
|
|
50
46
|
# Compress in production
|
@@ -60,6 +56,10 @@ module Volt
|
|
60
56
|
Csso.install(environment)
|
61
57
|
end
|
62
58
|
|
59
|
+
if Volt.config.compress_images
|
60
|
+
add_image_compression
|
61
|
+
end
|
62
|
+
|
63
63
|
@server.append_path(app_path)
|
64
64
|
|
65
65
|
volt_gem_lib_path = File.expand_path(File.join(File.dirname(__FILE__), '../../..'))
|
@@ -67,7 +67,17 @@ module Volt
|
|
67
67
|
|
68
68
|
add_asset_folders(@server)
|
69
69
|
|
70
|
-
|
70
|
+
|
71
|
+
# Setup ViewProcessor to parse views
|
72
|
+
Volt::ViewProcessor.setup(@environment)
|
73
|
+
|
74
|
+
# Use the cached env in production so it doesn't have to stat the FS
|
75
|
+
@environment = @environment.cached if Volt.env.production?
|
76
|
+
|
77
|
+
# Since the scope changes in builder blocks, we need to capture
|
78
|
+
# environment in closure
|
79
|
+
environment = @environment
|
80
|
+
|
71
81
|
builder.map '/assets' do
|
72
82
|
run environment
|
73
83
|
end
|
@@ -84,28 +94,30 @@ module Volt
|
|
84
94
|
end
|
85
95
|
|
86
96
|
if source_map_enabled
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
97
|
+
builder.map(maps_prefix) do
|
98
|
+
require 'rack/conditionalget'
|
99
|
+
require 'rack/etag'
|
100
|
+
use Rack::ConditionalGet
|
101
|
+
use Rack::ETag
|
102
|
+
run maps_app
|
94
103
|
end
|
104
|
+
end
|
105
|
+
end
|
95
106
|
|
107
|
+
def add_image_compression
|
108
|
+
if defined?(ImageOptim)
|
109
|
+
env = @environment
|
110
|
+
image_optim = ImageOptim.new({:pngout => false, :svgo => false})
|
96
111
|
|
112
|
+
processor = proc do |_context, data|
|
113
|
+
image_optim.optimize_image_data(data) || data
|
114
|
+
end
|
97
115
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
# source_maps = SourceMapServer.new(environment)
|
104
|
-
#
|
105
|
-
# builder.map(source_maps.prefix) do
|
106
|
-
# run source_maps
|
107
|
-
# end
|
108
|
-
# end
|
116
|
+
env.register_preprocessor 'image/gif', :image_optim, &processor
|
117
|
+
env.register_preprocessor 'image/jpeg', :image_optim, &processor
|
118
|
+
env.register_preprocessor 'image/png', :image_optim, &processor
|
119
|
+
env.register_preprocessor 'image/svg+xml', :image_optim, &processor
|
120
|
+
end
|
109
121
|
end
|
110
122
|
|
111
123
|
def add_asset_folders(environment)
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'sprockets-helpers'
|
2
|
+
|
3
|
+
module Volt
|
4
|
+
class SprocketsHelpersSetup
|
5
|
+
def initialize(env)
|
6
|
+
@env = env
|
7
|
+
|
8
|
+
setup_path_helpers
|
9
|
+
add_linking_in_asset_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup_path_helpers
|
13
|
+
digest = Volt.env.production?
|
14
|
+
|
15
|
+
# Configure Sprockets::Helpers (if necessary)
|
16
|
+
Sprockets::Helpers.configure do |config|
|
17
|
+
config.environment = @env
|
18
|
+
config.prefix = '/assets'
|
19
|
+
config.public_path = 'public'
|
20
|
+
config.debug = false#!Volt.env.production?
|
21
|
+
|
22
|
+
# Force to debug mode in development mode
|
23
|
+
# Debug mode automatically sets
|
24
|
+
# expand = true, digest = false, manifest = false
|
25
|
+
|
26
|
+
config.digest = digest
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
Sprockets::Helpers.digest = digest
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_linking_in_asset_path
|
35
|
+
@env.context_class.class_eval do
|
36
|
+
# We "freedom-patch" sprockets-helpers asset_path method to
|
37
|
+
# automatically link assets.
|
38
|
+
def asset_path(source, options = {})
|
39
|
+
uri = URI.parse(source)
|
40
|
+
return source if uri.absolute?
|
41
|
+
|
42
|
+
options[:prefix] = Sprockets::Helpers.prefix unless options[:prefix]
|
43
|
+
|
44
|
+
if Sprockets::Helpers.debug || options[:debug]
|
45
|
+
options[:manifest] = false
|
46
|
+
options[:digest] = false
|
47
|
+
options[:asset_host] = false
|
48
|
+
end
|
49
|
+
|
50
|
+
source_ext = File.extname(source)
|
51
|
+
|
52
|
+
if options[:ext] && source_ext != ".#{options[:ext]}"
|
53
|
+
uri.path << ".#{options[:ext]}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Link all assets out of the box
|
57
|
+
# Added by volt
|
58
|
+
link_asset(uri)
|
59
|
+
|
60
|
+
path = find_asset_path(uri, source, options)
|
61
|
+
if options[:expand] && path.respond_to?(:to_a)
|
62
|
+
path.to_a
|
63
|
+
else
|
64
|
+
path.to_s
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -67,8 +67,7 @@ module Volt
|
|
67
67
|
Opal.compile(code)
|
68
68
|
end
|
69
69
|
|
70
|
-
def self.setup
|
71
|
-
sprockets = $volt_app.sprockets
|
70
|
+
def self.setup(sprockets=$volt_app.sprockets)
|
72
71
|
sprockets.register_mime_type 'application/vtemplate', extensions: ['.html', '.email']
|
73
72
|
sprockets.register_transformer 'application/vtemplate', 'application/javascript', Volt::ViewProcessor.new(true)
|
74
73
|
end
|
@@ -64,7 +64,7 @@ class Promise
|
|
64
64
|
|
65
65
|
# When testing with rspec, add in a custom exception! method that doesn't
|
66
66
|
# swallow ExpectationNotMetError's.
|
67
|
-
if defined?(RSpec::Expectations::ExpectationNotMetError)
|
67
|
+
if defined?(RSpec) && defined?(RSpec::Expectations::ExpectationNotMetError)
|
68
68
|
def exception!(error)
|
69
69
|
if error.is_a?(RSpec::Expectations::ExpectationNotMetError)
|
70
70
|
raise error
|
data/lib/volt/version.rb
CHANGED
data/lib/volt/volt/app.rb
CHANGED
@@ -39,6 +39,17 @@ module Volt
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def link_clicked(url = '', event = nil)
|
42
|
+
target = nil
|
43
|
+
`target = $(event.target).attr('target');`
|
44
|
+
`if (!target) {`
|
45
|
+
`target = #{nil};`
|
46
|
+
`}`
|
47
|
+
|
48
|
+
if target.present? && target != '_self'
|
49
|
+
# Don't handle if they are opening in a new window
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
|
42
53
|
# Skip when href == ''
|
43
54
|
return false if url.blank?
|
44
55
|
|
@@ -2,31 +2,54 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gem 'volt', path: '../../../'
|
4
4
|
|
5
|
-
#
|
5
|
+
# volt uses mongo as the default data store.
|
6
|
+
gem 'volt-mongo'
|
6
7
|
|
8
|
+
# The following gem's are optional for themeing
|
7
9
|
# Twitter bootstrap
|
8
|
-
gem 'volt-bootstrap'
|
10
|
+
gem 'volt-bootstrap', '~> 0.0.10'
|
9
11
|
|
10
12
|
# Simple theme for bootstrap, remove to theme yourself.
|
11
|
-
gem 'volt-bootstrap_jumbotron_theme'
|
13
|
+
gem 'volt-bootstrap_jumbotron_theme', '~> 0.1.0'
|
12
14
|
|
13
|
-
|
14
|
-
gem 'volt-user_templates'
|
15
|
+
# User templates for login, signup, and logout menu.
|
16
|
+
gem 'volt-user_templates', '~> 0.4.0'
|
15
17
|
|
16
|
-
#
|
17
|
-
gem 'volt-
|
18
|
+
# Add ability to send e-mail from apps.
|
19
|
+
gem 'volt-mailer', '~> 0.1.0'
|
20
|
+
|
21
|
+
gem 'volt-fields'
|
18
22
|
|
19
|
-
|
23
|
+
# Use rbnacl for message bus encrpytion
|
24
|
+
# (optional, if you don't need encryption, disable in app.rb and remove)
|
25
|
+
#
|
26
|
+
# Message Bus encryption is not supported on Windows at the moment.
|
27
|
+
platform :ruby, :jruby do
|
28
|
+
gem 'rbnacl', require: false
|
29
|
+
gem 'rbnacl-libsodium', require: false
|
30
|
+
end
|
20
31
|
|
21
|
-
|
32
|
+
# Asset compilation gems, they will be required when needed.
|
33
|
+
gem 'csso-rails', '~> 0.3.4', require: false
|
34
|
+
gem 'uglifier', '>= 2.4.0', require: false
|
35
|
+
|
36
|
+
group :test do
|
37
|
+
# Testing dependencies
|
38
|
+
gem 'rspec', '~> 3.2.0'
|
39
|
+
gem 'opal-rspec', '~> 0.4.2'
|
40
|
+
gem 'capybara', '~> 2.4.2'
|
41
|
+
gem 'selenium-webdriver', '~> 2.43.0'
|
42
|
+
gem 'chromedriver2-helper', '~> 0.0.8'
|
43
|
+
gem 'poltergeist', '~> 1.5.0'
|
44
|
+
end
|
22
45
|
|
23
46
|
# Server for MRI
|
24
47
|
platform :mri do
|
48
|
+
# The implementation of ReadWriteLock in Volt uses concurrent ruby and ext helps performance.
|
49
|
+
gem 'concurrent-ruby-ext', '~> 0.8.0'
|
50
|
+
|
51
|
+
# Thin is the default volt server, you Puma is also supported
|
25
52
|
gem 'thin', '~> 1.6.0'
|
53
|
+
# gem 'puma'
|
26
54
|
gem 'bson_ext', '~> 1.9.0'
|
27
55
|
end
|
28
|
-
|
29
|
-
# Server for jruby
|
30
|
-
platform :jruby do
|
31
|
-
gem 'jubilee'
|
32
|
-
end
|