volt 0.4.5 → 0.4.7

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: 305dc41dfe5a91e98dafe5bf8c8fba5ffa852a75
4
- data.tar.gz: ba78dc36acf5a28d045370705ec0f3951da6c63c
3
+ metadata.gz: 6dc382e28cc1e24d1fc62104d3eac49143a473f0
4
+ data.tar.gz: d9cfbd13dfb26f582c15f11dde6167ce107f00c3
5
5
  SHA512:
6
- metadata.gz: 55c12c5bf660a07a4d16eb862e35d6b1997078123ae8f1433c290d3bc74d9920a07208cd82e0c6ec625e843ec752d9f9fd3a0c3968fda15d083219c7d90d295b
7
- data.tar.gz: 9c708dca0c19de659bccd3f9827fa6846f571bcfe562db08c5969f80aa95adc8e9073d84cd511f984e7a5dec5143a47b311b4b9bb0d38f2261c6d7df609c5e07
6
+ metadata.gz: c40b106ac5195a1df566437905708891744f290e8386c29897c235657d9e4c945ae87dda6582e908261b04c6510583478aabdcd994d78ba1f82468d306a62739
7
+ data.tar.gz: ff4b2bc4553bc7829ab50162c3f848cf98535d06eb5b03af03cc0840066135de5c8fe27568b5798fe04972c10e6a2bb4b4c1839b1efbc4890533d64595fb2937
data/Readme.md CHANGED
@@ -68,6 +68,8 @@ You can access the volt console with:
68
68
  3. [Each Binding](#each-binding)
69
69
  4. [Attribute Bindings](#attribute-bindings)
70
70
  2. [Models](#models)
71
+ 1. [Reactive Models](#reactive-models)
72
+ 2. [Model Events](#model-events)
71
73
  3. [Components](#components)
72
74
  1. [Assets](#assets)
73
75
  2. [Component Generator](#component-generator)
@@ -325,6 +327,25 @@ Above I mentioned that Volt comes with many different models accessable from a c
325
327
 
326
328
  Because all models provided by Volt are wrapped in a ReactiveValue, you can register listeners on them and be updated when values change. You can also call methods on their values and get updates when the source's change. Bindings also setup listeners. Models should be the main place you store all data in Volt. While you can use ReactiveValue's manually, most of the time you will want to just use something like the page model.
327
329
 
330
+ ## Model Events
331
+
332
+ Models trigger events when their data is updated. Currently models emit three events: changed, added, and removed. For example:
333
+
334
+ model = Model.new
335
+
336
+ model._name.on('changed') { puts 'name changed' }
337
+ model._name = 'Ryan'
338
+ # => name changed
339
+
340
+ model._items.on('added') { puts 'item added' }
341
+ model._items << 1
342
+ # => item added
343
+
344
+ model._items.on('removed') { puts 'item removed' }
345
+ model._items.delete_at(0)
346
+ # => item removed
347
+
348
+
328
349
  # Controllers
329
350
 
330
351
  A controller can be any class in Volt, however it is common to have that class inherit from ModelController. A model controller lets you specify a model that the controller works off of. This is a common pattern in Volt. To assign the current model, simply set @model to one of the provided models in the initializer.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.5
1
+ 0.4.7
File without changes
data/docs/WHY.md ADDED
@@ -0,0 +1,50 @@
1
+ # Why Volt?
2
+
3
+ Volt is a new web framework. You use Ruby for both your client and server code. Volt helps you break your code into reusable components. It handles managing all assets and dependencies for you. Volt automatically updates your pages for you when your model data changes and sync's that data to the database for you. By providing reusable structure and handling common tasks, Volt lets you build web app's really fast!
4
+
5
+ # Features
6
+
7
+ ## Components
8
+
9
+ Volt projects are broken into components. Components are easy to create and simple to reuse. They are easily shared and only require one line of code to insert into your project. Volt provides many common components out of the box.
10
+
11
+ ## Reactive
12
+
13
+ Data in volt is reactive by default. Changes to the data is automatically updated in the DOM.
14
+
15
+
16
+ ## Data Syncing
17
+
18
+ A lot of modern web development is moving data between the front-end to the back-end. Volt eliminates all of that work. Model's on the front-end automatically sync to the back-end, and vice versa. Validations are run on both sides for security. Models on the front-end are automatically updated whenever they are changed anywhere else (another browser, a background task, etc..)
19
+
20
+
21
+ ## Speed
22
+
23
+ Volt's reactive objects contain extra data about how to propigate events. Things that don't need to be updated when data changes aren't. Volt uses an intellegent managed draw cycle to do efficient DOM updates. Only the changed part of the page is re-rendered.
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+ # Why Ruby
40
+
41
+ In web development today, JavaScript gets to be the default language by virtue of being in the browser. JavaScript is a very good language, but it has a lot of warts. (See http://wtfjs.com/ for some great examples) Some of these can introduce bugs, others are just difficult to deal with. JavaScript was rushed to market quickly and standardized very quickly. Ruby was used by a small community for years while most of the kinks were worked out. Ruby also has some great concepts such as [uniform access](http://en.wikipedia.org/wiki/Uniform_access_principle), [mixin's](http://en.wikipedia.org/wiki/Mixin), [duck typing](http://en.wikipedia.org/wiki/Duck_typing), and [blocks](http://yehudakatz.com/2012/01/10/javascript-needs-blocks/) to name a few. While many of these features can be implemented in JavaScript in userland, few are standardardized and the solutions are seldom eloquent.
42
+
43
+ [5,10,1].sort()
44
+ // [1, 10, 5]
45
+
46
+ Uniform access and duck typing provides us with the ability to make reactive objects that have the exact same interface as a normal object. This is a big win, nothing new to learn to do reactive programming. They can also be used interchangably with regular objects.
47
+
48
+ # Why Opal
49
+
50
+ Opal is really an increadiable project, and the core team has done a great job. Ruby and JavaScript are similar in a lot of ways. This lets Opal compile to JavaScript that is very readable. This also means that Opal's performance is great. You'll find that in most cases Ruby code runs with no performance penality compared to the eqivilent JavaScript code.
data/lib/volt/cli.rb CHANGED
@@ -29,6 +29,9 @@ class CLI < Thor
29
29
  # source maps and non-source maps.
30
30
  if File.exists?("config.ru") && File.exists?("Gemfile")
31
31
  FileUtils.rm_rf("tmp/.")
32
+ else
33
+ say("Current folder is not a Volt project", :red)
34
+ return
32
35
  end
33
36
 
34
37
  ENV['SERVER'] = 'true'
@@ -44,7 +47,7 @@ class CLI < Thor
44
47
  #
45
48
  # EM.run do
46
49
  # thin = Rack::Handler.get("thin")
47
- # thin.run(Server.new.app, Port: 5000)
50
+ # thin.run(Server.new.app, Port: 3000)
48
51
  # end
49
52
  end
50
53
 
data/lib/volt/console.rb CHANGED
@@ -19,7 +19,7 @@ class Console
19
19
 
20
20
  app_path = File.expand_path(File.join(Dir.pwd, "app"))
21
21
  component_paths = ComponentPaths.new
22
- component_paths.add_tasks_to_load_path
22
+ component_paths.setup_components_load_path
23
23
 
24
24
  Pry.config.prompt_name = 'volt'
25
25
 
@@ -91,9 +91,9 @@ class AttributeBinding < BaseBinding
91
91
  # aren't responsible for it being there.
92
92
  case @attribute_name
93
93
  when 'value'
94
- element.off('input.attrbind')
94
+ element.off('input.attrbind', nil)
95
95
  when 'checked'
96
- element.off('change.attrbind')
96
+ element.off('change.attrbind', nil)
97
97
  end
98
98
 
99
99
  if @update_listener
data/lib/volt/server.rb CHANGED
@@ -57,7 +57,6 @@ class Server
57
57
 
58
58
  def setup_change_listener
59
59
  # Setup the listeners for file changes
60
- puts "Listen for changes at #{@app_path}"
61
60
  listener = Listen.to("#{@app_path}/") do |modified, added, removed|
62
61
  ChannelHandler.send_message_all(nil, 'reload')
63
62
  end
@@ -94,7 +93,7 @@ class Server
94
93
 
95
94
  # Handle socks js connection
96
95
  if RUBY_PLATFORM != 'java'
97
- component_paths.add_tasks_to_load_path
96
+ component_paths.setup_components_load_path
98
97
  ChannelHandler.dispatcher = Dispatcher.new
99
98
 
100
99
  @app.map "/channel" do
@@ -2,7 +2,7 @@ require 'stringio'
2
2
  require 'volt'
3
3
  require 'volt/server/template_parser'
4
4
  require 'volt/server/component_templates'
5
- require 'volt/server/rack/component_files'
5
+ require 'volt/server/rack/asset_files'
6
6
 
7
7
  class ComponentHandler
8
8
  def initialize(component_paths)
@@ -17,8 +17,8 @@ class ComponentHandler
17
17
 
18
18
  code = ''
19
19
 
20
- component_files = ComponentFiles.new(component_name, @component_paths, true)
21
- component_files.component_paths.each do |component_path, component_name|
20
+ asset_files = AssetFiles.new(component_name, @component_paths)
21
+ asset_files.component_paths.each do |component_path, component_name|
22
22
  code << ComponentTemplates.new(component_path, component_name).code
23
23
  code << "\n\n"
24
24
  end
@@ -0,0 +1,106 @@
1
+ # Used to get a list of the assets from the dependencies
2
+ class AssetFiles
3
+ def initialize(component_name, component_paths)
4
+ @component_paths = component_paths
5
+ @assets = []
6
+ @included_components = {}
7
+ @components = []
8
+
9
+ component('volt')
10
+ component(component_name)
11
+ end
12
+
13
+ def load_dependencies(path)
14
+ if path
15
+ dependencies_file = File.join(path, "config/dependencies.rb")
16
+ else
17
+ raise "Unable to find component #{component_name.inspect}"
18
+ end
19
+
20
+ if File.exists?(dependencies_file)
21
+ # Run the dependencies file in this asset files context
22
+ code = File.read(dependencies_file)
23
+ instance_eval(code)
24
+ end
25
+ end
26
+
27
+ def component(name)
28
+ unless @included_components[name]
29
+ # Get the path to the component
30
+ path = @component_paths.component_path(name)
31
+
32
+ # Track that we added
33
+ @included_components[name] = true
34
+
35
+ # Load the dependencies
36
+ load_dependencies(path)
37
+
38
+ # Add any assets
39
+ add_assets(path)
40
+ @components << [path, name]
41
+ end
42
+ end
43
+
44
+ def components
45
+ @included_components.keys
46
+ end
47
+
48
+ def javascript_file(url)
49
+ @assets << [:javascript_file, url]
50
+ end
51
+
52
+ def css_file(url)
53
+ @assets << [:css_file, url]
54
+ end
55
+
56
+ def component_paths
57
+ return @components
58
+ end
59
+
60
+ def add_assets(path)
61
+ asset_folder = File.join(path, 'assets')
62
+ if File.directory?(asset_folder)
63
+ @assets << [:folder, asset_folder]
64
+ end
65
+ end
66
+
67
+
68
+ def javascript_files(opal_files)
69
+ javascript_files = []
70
+ @assets.each do |type, path|
71
+ case type
72
+ when :folder
73
+ javascript_files += Dir["#{path}/**/*.js"].map {|folder| '/assets' + folder[path.size..-1] }
74
+ when :javascript_file
75
+ javascript_files << path
76
+ end
77
+ end
78
+
79
+ opal_js_files = []
80
+ if Volt.source_maps?
81
+ opal_js_files += opal_files.environment['volt/page/page'].to_a.map {|v| '/assets/' + v.logical_path + '?body=1' }
82
+ else
83
+ opal_js_files << '/assets/volt/page/page.js'
84
+ end
85
+ opal_js_files << '/components/home.js'
86
+
87
+ javascript_files += opal_js_files
88
+
89
+ return javascript_files
90
+ end
91
+
92
+ def css_files
93
+ css_files = []
94
+ @assets.each do |type, path|
95
+ case type
96
+ when :folder
97
+ css_files += Dir["#{path}/**/*.{css,scss}"].map {|folder| '/assets' + folder[path.size..-1].gsub(/[.]scss$/, '') }
98
+ when :css_file
99
+ css_files << path
100
+ end
101
+ end
102
+
103
+ return css_files
104
+ end
105
+
106
+ end
@@ -1,3 +1,4 @@
1
+ # ComponentPaths gives an array of every folder where you find a component.
1
2
  class ComponentPaths
2
3
  def initialize(root=nil)
3
4
  @root = root || Dir.pwd
@@ -27,6 +28,7 @@ class ComponentPaths
27
28
  return files.flatten
28
29
  end
29
30
 
31
+ # returns an array of every folder that is a component
30
32
  def components
31
33
  return @components if @components
32
34
 
@@ -45,7 +47,8 @@ class ComponentPaths
45
47
  return @components
46
48
  end
47
49
 
48
- def add_tasks_to_load_path
50
+ # Makes each components classes available on the load path
51
+ def setup_components_load_path
49
52
  components.each do |name,component_folders|
50
53
  component_folders.each do |component_folder|
51
54
  Dir["#{component_folder}/tasks"].each do |tasks_folder|
@@ -55,6 +58,7 @@ class ComponentPaths
55
58
  end
56
59
  end
57
60
 
61
+ # Returns the path for a specific component
58
62
  def component_path(name)
59
63
  folders = components[name]
60
64
 
@@ -1,4 +1,4 @@
1
- require 'volt/server/rack/component_files'
1
+ require 'volt/server/rack/asset_files'
2
2
  require 'volt/router/routes'
3
3
 
4
4
  # Serves the main pages
@@ -5,8 +5,10 @@ class OpalFiles
5
5
  attr_reader :environment
6
6
 
7
7
  def initialize(builder, app_path, component_paths)
8
- ::Opal::Processor.source_map_enabled = Volt.source_maps?
9
- # Opal::Processor.arity_check_enabled = true
8
+ Opal::Processor.source_map_enabled = Volt.source_maps?
9
+
10
+ # Don't run arity checks in production
11
+ # Opal::Processor.arity_check_enabled = !Volt.env.production?
10
12
  # Opal::Processor.dynamic_require_severity = :raise
11
13
 
12
14
  @component_paths = component_paths
@@ -0,0 +1,25 @@
1
+ if RUBY_PLATFORM != 'opal'
2
+ require 'volt/server/rack/asset_files'
3
+
4
+ describe AssetFiles do
5
+ before do
6
+ spec_app_root = File.join(File.dirname(__FILE__), "../..")
7
+
8
+ path_to_main = File.join(File.dirname(__FILE__), "../../app/main")
9
+ @component_paths = ComponentPaths.new(spec_app_root)
10
+ end
11
+
12
+ it "should return the dependencies list" do
13
+ main = AssetFiles.new("main", @component_paths)
14
+
15
+ components = main.components
16
+ expect(components).to eq(['volt', 'main', 'shared', 'bootstrap', "slideshow"])
17
+ end
18
+
19
+ it "should list all JS files" do
20
+ main = AssetFiles.new("main", @component_paths)
21
+
22
+ expect(main.javascript_files(nil)).to eq(["/assets/js/jquery-2.0.3.js", "/assets/js/sockjs-0.2.1.min.js", "/assets/js/bootstrap.js", "/assets/js/test2.js", "/assets/js/test3.js", "/assets/js/test1.js", "/assets/volt/page/page.js", "/components/home.js"])
23
+ end
24
+ end
25
+ end
@@ -1,4 +1,4 @@
1
- get "/about", _controller: 'about'
1
+ get "/about", _page: 'about'
2
2
 
3
3
  # The main route
4
4
  get '/'
@@ -1,5 +1,5 @@
1
1
  <:title>
2
- {#template params._controller.or('home'), "title"}
2
+ {#template params._page.or('home'), "title"}
3
3
  </:title>
4
4
 
5
5
  <:body>
@@ -14,7 +14,7 @@
14
14
  <h3 class="text-muted">Project name</h3>
15
15
  </div>
16
16
 
17
- {#template params._controller.or('home')}
17
+ {#template params._page.or('home')}
18
18
 
19
19
  <div class="footer">
20
20
  <p>&copy; Company 2014</p>
@@ -24,7 +24,7 @@
24
24
  </:body>
25
25
 
26
26
  <:nav>
27
- <li class="{#if params._controller.or('') == page}active{/}">
27
+ <li class="{#if params._page.or('') == page}active{/}">
28
28
  <a href="/{page}">{text}</a>
29
29
  </li>
30
30
  </:nav>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: volt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Stout
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-22 00:00:00.000000000 Z
11
+ date: 2014-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -297,11 +297,13 @@ files:
297
297
  - app/volt/assets/css/notices.css.scss
298
298
  - app/volt/assets/js/jquery-2.0.3.js
299
299
  - app/volt/assets/js/sockjs-0.2.1.min.js
300
+ - app/volt/config/dependencies.rb
300
301
  - app/volt/tasks/channel_tasks.rb
301
302
  - app/volt/tasks/store_tasks.rb
302
303
  - app/volt/views/notices/index.html
303
304
  - bin/volt
304
305
  - docs/GETTING_STARTED.md
306
+ - docs/WHY.md
305
307
  - lib/volt.rb
306
308
  - lib/volt/benchmark/benchmark.rb
307
309
  - lib/volt/cli.rb
@@ -374,7 +376,7 @@ files:
374
376
  - lib/volt/server/component_handler.rb
375
377
  - lib/volt/server/component_templates.rb
376
378
  - lib/volt/server/if_binding_setup.rb
377
- - lib/volt/server/rack/component_files.rb
379
+ - lib/volt/server/rack/asset_files.rb
378
380
  - lib/volt/server/rack/component_paths.rb
379
381
  - lib/volt/server/rack/index_files.rb
380
382
  - lib/volt/server/rack/opal_files.rb
@@ -401,7 +403,7 @@ files:
401
403
  - spec/models/string_extensions_spec.rb
402
404
  - spec/page/sub_context_spec.rb
403
405
  - spec/router/routes_spec.rb
404
- - spec/server/rack/component_files_spec.rb
406
+ - spec/server/rack/asset_files_spec.rb
405
407
  - spec/server/rack/component_paths_spec.rb
406
408
  - spec/server/template_parser_spec.rb
407
409
  - spec/spec_helper.rb
@@ -486,7 +488,7 @@ test_files:
486
488
  - spec/models/string_extensions_spec.rb
487
489
  - spec/page/sub_context_spec.rb
488
490
  - spec/router/routes_spec.rb
489
- - spec/server/rack/component_files_spec.rb
491
+ - spec/server/rack/asset_files_spec.rb
490
492
  - spec/server/rack/component_paths_spec.rb
491
493
  - spec/server/template_parser_spec.rb
492
494
  - spec/spec_helper.rb
@@ -1,109 +0,0 @@
1
- require 'volt/server/rack/component_paths'
2
- require 'volt'
3
-
4
- # Takes in the path to a component and gets all other components
5
- # required from this one
6
- class ComponentFiles
7
- def initialize(component_name, component_paths, main_component=false)
8
- @component_name = component_name
9
- @component_paths = component_paths
10
- @asset_folders = []
11
- @components = [component_name]
12
- @main_component = main_component
13
-
14
- if @main_component
15
- # puts "ADD VOLT"
16
- # Add in volt's JS files first
17
- component('volt')
18
- end
19
-
20
- load_child_components
21
- add_asset_folder(component_name)
22
- end
23
-
24
- def components
25
- @components
26
- end
27
-
28
- def component(name)
29
- # Load any sub-requires
30
- child_files = ComponentFiles.new(name, @component_paths)
31
- new_components = child_files.components
32
-
33
- # remove any we already have
34
- new_components = new_components - @components
35
- new_components.each {|nc| add_asset_folder(nc) }
36
-
37
- @components += new_components
38
-
39
- return @components
40
- end
41
-
42
- def add_asset_folder(component_name)
43
- path = path_to_component(component_name)
44
-
45
- asset_folder = File.join(path, 'assets')
46
- if File.directory?(asset_folder)
47
- @asset_folders << asset_folder
48
- end
49
- end
50
-
51
- def path_to_component(name=nil)
52
- @component_paths.component_path(name || @component_name)
53
- end
54
-
55
- def component_paths
56
- @components.map {|c| [path_to_component(c), c] }
57
- end
58
-
59
- def load_child_components
60
- path = path_to_component
61
- if path
62
- dependencies_file = File.join(path_to_component, "config/dependencies.rb")
63
- else
64
- raise "Unable to find component #{@component_name.inspect}"
65
- end
66
-
67
- if File.exists?(dependencies_file)
68
- # Run the dependencies file in this ComponentFiles context
69
- code = File.read(dependencies_file)
70
- instance_eval(code)
71
- end
72
- end
73
-
74
- # Returns every asset folder that is included from this component.
75
- # This means this components assets folder and any in the dependency chain.
76
- def asset_folders
77
- files = []
78
- @asset_folders.each do |asset_folder|
79
- files << yield(asset_folder)
80
- end
81
-
82
- return files.flatten
83
- end
84
-
85
-
86
- def javascript_files(opal_files)
87
- javascript_files = asset_folders do |asset_folder|
88
- Dir["#{asset_folder}/**/*.js"].map {|path| '/assets' + path[asset_folder.size..-1] }
89
- end
90
-
91
- opal_js_files = []
92
- if Volt.source_maps?
93
- opal_js_files += opal_files.environment['volt/page/page'].to_a.map {|v| '/assets/' + v.logical_path + '?body=1' }
94
- else
95
- opal_js_files << '/assets/volt/page/page.js'
96
- end
97
- opal_js_files << '/components/home.js'
98
-
99
- javascript_files.insert(2, *opal_js_files)
100
-
101
- return javascript_files
102
- end
103
-
104
- def css_files
105
- asset_folders do |asset_folder|
106
- Dir["#{asset_folder}/**/*.{css,scss}"].map {|path| '/assets' + path[asset_folder.size..-1].gsub(/[.]scss$/, '') }
107
- end
108
- end
109
- end
@@ -1,25 +0,0 @@
1
- if RUBY_PLATFORM != 'opal'
2
- require 'volt/server/rack/component_files'
3
-
4
- describe ComponentFiles do
5
- before do
6
- spec_app_root = File.join(File.dirname(__FILE__), "../..")
7
-
8
- path_to_main = File.join(File.dirname(__FILE__), "../../app/main")
9
- @component_paths = ComponentPaths.new(spec_app_root)
10
- end
11
-
12
- it "should return the dependencies list" do
13
- main = ComponentFiles.new("main", @component_paths)
14
-
15
- components = main.components
16
- expect(components).to eq(['main', 'shared', 'bootstrap', "slideshow"])
17
- end
18
-
19
- it "should list all JS files" do
20
- main = ComponentFiles.new("main", @component_paths)
21
-
22
- expect(main.javascript_files(nil)).to eq(["/assets/js/test2.js", "/assets/js/bootstrap.js", "/assets/volt/page/page.js", "/components/home.js", "/assets/js/test3.js", "/assets/js/test1.js"])
23
- end
24
- end
25
- end