volt 0.9.5.pre4 → 0.9.5.pre5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +13 -5
  4. data/app/volt/assets/css/{notices.css.scss → notices.scss} +0 -0
  5. data/app/volt/models/active_volt_instance.rb +1 -1
  6. data/app/volt/tasks/live_query/live_query.rb +11 -3
  7. data/app/volt/tasks/store_tasks.rb +14 -17
  8. data/lib/volt/cli.rb +22 -0
  9. data/lib/volt/cli/asset_compile.rb +63 -63
  10. data/lib/volt/cli/base_index_renderer.rb +26 -0
  11. data/lib/volt/cli/generate.rb +1 -1
  12. data/lib/volt/config.rb +1 -0
  13. data/lib/volt/controllers/model_controller.rb +37 -1
  14. data/lib/volt/extra_core/array.rb +22 -0
  15. data/lib/volt/models/array_model.rb +7 -1
  16. data/lib/volt/models/errors.rb +1 -1
  17. data/lib/volt/models/field_helpers.rb +36 -21
  18. data/lib/volt/models/model.rb +16 -0
  19. data/lib/volt/models/validations/validations.rb +21 -6
  20. data/lib/volt/models/validators/type_validator.rb +35 -3
  21. data/lib/volt/page/bindings/content_binding.rb +1 -1
  22. data/lib/volt/page/bindings/event_binding.rb +40 -16
  23. data/lib/volt/page/document_events.rb +8 -6
  24. data/lib/volt/reactive/reactive_array.rb +18 -1
  25. data/lib/volt/server/forking_server.rb +7 -1
  26. data/lib/volt/server/html_parser/attribute_scope.rb +26 -0
  27. data/lib/volt/server/html_parser/component_view_scope.rb +30 -22
  28. data/lib/volt/server/middleware/default_middleware_stack.rb +6 -1
  29. data/lib/volt/server/rack/asset_files.rb +5 -3
  30. data/lib/volt/server/rack/opal_files.rb +35 -23
  31. data/lib/volt/server/rack/sprockets_helpers_setup.rb +71 -0
  32. data/lib/volt/server/template_handlers/view_processor.rb +1 -2
  33. data/lib/volt/utils/promise_extensions.rb +1 -1
  34. data/lib/volt/version.rb +1 -1
  35. data/lib/volt/volt/app.rb +0 -2
  36. data/lib/volt/volt/client_setup/browser.rb +11 -0
  37. data/spec/apps/kitchen_sink/Gemfile +37 -14
  38. data/spec/apps/kitchen_sink/app/main/config/routes.rb +3 -0
  39. data/spec/apps/kitchen_sink/app/main/controllers/events_controller.rb +26 -0
  40. data/spec/apps/kitchen_sink/app/main/views/events/index.html +30 -0
  41. data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +3 -0
  42. data/spec/apps/kitchen_sink/app/main/views/main/yield.html +1 -6
  43. data/spec/apps/kitchen_sink/app/main/views/{yield-component → yield_component}/index.html +0 -0
  44. data/spec/extra_core/array_spec.rb +26 -0
  45. data/spec/integration/bindings_spec.rb +9 -0
  46. data/spec/integration/event_spec.rb +19 -0
  47. data/spec/models/array_model_spec.rb +13 -0
  48. data/spec/models/field_helpers_spec.rb +2 -2
  49. data/spec/models/validations_spec.rb +31 -0
  50. data/spec/models/validators/type_validator_spec.rb +47 -1
  51. data/spec/reactive/reactive_array_spec.rb +46 -0
  52. data/spec/server/forking_server_spec.rb +27 -0
  53. data/spec/server/html_parser/view_scope_spec.rb +44 -0
  54. data/spec/server/rack/asset_files_spec.rb +2 -2
  55. data/templates/project/Gemfile.tt +8 -0
  56. data/templates/project/config/app.rb.tt +2 -1
  57. data/volt.gemspec +1 -1
  58. 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
- # if this attribute has bindings
18
- if binding_count > 0
19
- if binding_count > 1
20
- # Multiple bindings
21
- elsif parts.size == 1 && binding_count == 1
22
- # A single binding
23
- getter = value[2...-2].strip
24
- data_hash << "#{name.inspect} => Proc.new { #{getter} }"
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
- setter = getter_to_setter(getter)
27
- data_hash << "#{(name + '=').inspect} => Proc.new { |val| #{setter} }"
31
+ data_hash << "#{name.inspect} => Proc.new { #{getter} }"
28
32
 
29
- # Add an _parent fetcher. Useful for things like volt-fields to get the parent model.
30
- parent = parent_fetcher(getter)
33
+ setter = getter_to_setter(getter)
34
+ data_hash << "#{(name + '=').inspect} => Proc.new { |val| #{setter} }"
31
35
 
32
- # TODO: This adds some overhead, perhaps there is a way to compute this dynamically on the
33
- # front-end.
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
- # Add a _last_method property. This is useful
37
- data_hash << "#{(name + '_last_method').inspect} => #{last_method_name(getter).inspect}"
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
- rack_app.use Rack::ShowExceptions
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
- # [[:url, '/somefile.js'], [:body, 'var inlinejs = true;']]
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
- env = @enviroment
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
- builder.map(maps_prefix) do
88
- require 'rack/conditionalget'
89
- require 'rack/etag'
90
- use Rack::ConditionalGet
91
- use Rack::ETag
92
- run maps_app
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
- # map server.source_maps.prefix do
99
- # run server.source_maps
100
- # end
101
-
102
- # if Volt.source_maps?
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
@@ -1,5 +1,5 @@
1
1
  module Volt
2
2
  module Version
3
- STRING = '0.9.5.pre4'
3
+ STRING = '0.9.5.pre5'
4
4
  end
5
5
  end
data/lib/volt/volt/app.rb CHANGED
@@ -99,8 +99,6 @@ module Volt
99
99
  setup_postboot_middleware
100
100
 
101
101
  start_message_bus
102
-
103
- Volt::ViewProcessor.setup
104
102
  end
105
103
  end
106
104
 
@@ -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
- # The following gem's are optional for themeing
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
- gem 'volt-fields'
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
- # use mongo for data store while testing
17
- gem 'volt-mongo'
18
+ # Add ability to send e-mail from apps.
19
+ gem 'volt-mailer', '~> 0.1.0'
20
+
21
+ gem 'volt-fields'
18
22
 
19
- gem 'opal'
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
- gem 'concurrent-ruby-ext'
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