[![Gem Version](https://badge.fury.io/rb/volt.png)](http://badge.fury.io/rb/volt) [![Code Climate](https://codeclimate.com/github/voltrb/volt.png)](https://codeclimate.com/github/voltrb/volt) [![Build Status](https://travis-ci.org/voltrb/volt.png?branch=master)](https://travis-ci.org/voltrb/volt) # Volt NOTE: VOLT IS STILL IN DEVELOPMENT, DON'T USE IT FOR ANYTHING SERIOUS YET Volt is a ruby web framework where your ruby code runs on both the server and the client (via [opal](https://github.com/opal/opal).) The dom automatically update as the user interacts with the page. Page state can be stored in the url, if the user hits a url directly, the HTML will first be rendered on the server for faster load times and easier indexing by search engines. Instead of syncing data between the client and server via HTTP, volt uses a persistent connection between the client and server. When data updated on one client, it is updated in the database and any other listening clients. (With almost no setup code needed) Pages HTML is written in a handlebars like template language. Volt uses data flow/reactive programming to automatically and intellegently propigate changes to the dom (or anything other code wanting to know when a value updates) When something in the dom changes, Volt intellegent updates only the nodes that need to be changed. ## Goals Volt has the following goals: 1. Developer happieness 2. Write once on the client and the server 3. Automatic data syncing between client and server 4. Apps are built as nested components. Components can be shared (via gems) 5. Concurrent. Volt provides tools to simplify concurrency. Component rendering is done in parallel on the server. 6. Intellegent asset management 7. Secure (shouldn't need to be said, but it does) 8. Be fast/light 9. Understandable code base 10. Control Upgradeability # Road Map Many of the core Volt features are implemented. We still have a bit to go before 1.0, most of it involving models. 1. Database storing models 2. Model validations (client and server side) 3. Reactive model queries 4. Reactive Enumerators with Blocks (.map .count, etc...) 5. Full managed render loop (for fast rendering) 6. Fix N+1 issue with some reactive values (I know how to fix, just haven't gotten around to doing it) # VOLT guide This guide will take you through creating a basic web application in Volt. This tutorial assumes a basic knowledge of ruby and web development. To get started, install volt: gem install volt Then create a new project: volt new project_name This will setup a basic project. Now lets run the server. volt server You can access the volt console with: volt console # Guide Sections 1. [Rendering](#rendering) 1. [Reactive Values](#reactive-values) 2. [Bindings](#bindings) 1. [Content Binding](#content-binding) 2. [If Binding](#if-binding) 3. [Each Binding](#each-binding) 4. [Attribute Bindings](#attribute-bindings) 2. [Models](#models) 3. [Components](#components) 1. [Assets](#assets) 2. [Component Generator](#component-generator) 4. [Controls](#controls) 5. [Routes](#routes) 1. [Routes file](#routes-file) # Rendering When a user interacts with a web page, typically we want to do two things: 1. Change application state 2. Update the DOM For example when a user clicks to add a new todo item to a todo list, we might create a JavaScript object to represent the todo item, then add an item to the list's DOM. A lot of work needs to be done to make sure that the JavaScript object and the DOM always stay in sync. Recently the idea of "reactive programming" has been used to simplify maintaining the DOM. The idea is instead of having event handlers that manage a model (or JavaScript object) and manage the DOM, we have event handlers that manage reactive data models. We describe our DOM layer in a declarative way so that it automatically knows how to render our data models. ## Reactive Value's To build bindings, Volt provides the ReactiveValue class. This wraps any object in a reactive interface. To create a ReactiveValue, simply pass the object you want to wrap as the first argument to new. ```ruby a = ReactiveValue.new("my object") # => @"my object" ``` When .inspect is called on a ReactiveValue (like in the console), an @ is placed infront of the value's inspect string, so you know its reactive. When you call a method on a ReactiveValue, you get back a new reactive value that depends on the previous one. It remebers how it was created and you can call .cur on it any time to get its current value, which will be computed based off of the first reactive value. (Keep in mind below that + is a method call, the same as a.+(b) in ruby.) ```ruby a = ReactiveValue.new(1) a.reactive? # => true a.cur # => 1 b = a + 5 b.reactive? # => true b.cur # => 6 a.cur = 2 b.cur # => 7 ``` This provides the backbone for reactive programming. We setup computation/flow graphs instead of doing an actual calcuation. Calling .cur (or .inspect, .to_s, etc..) runs the computation and returns the current value at that time, based on all of its dependencies. ReactiveValue's also let you setup listeners and trigger events: ```ruby a = ReactiveValue.new(0) a.on('changed') { puts "A changed" } a.trigger!('changed') # => A Changed ``` These events propigate to any reactive value's created off of a reactive value. ```ruby a = ReactiveValue.new(1) b = a + 5 b.on('changed') { puts "B changed" } a.trigger!('changed') # => B changed ``` This event flow lets us know when an object has changed, so we can update everything that depended on that object. Lastly, we can also pass in other reactive value's as arguments to methods on a reactive value. The dependencies will be tracked for both and events will propigate down from both. (Also, note that doing .cur = to update the current value triggers a "changed" event.) ```ruby a = ReactiveValue.new(1) b = ReactiveValue.new(2) c = a + b a.on('changed') { puts "A changed" } b.on('changed') { puts "B changed" } c.on('changed') { puts "C changed" } a.cur = 3 # => A changed # => C changed b.cur = 5 # => B changed # => C changed ``` ### Truthy Checks: .true?, .false?, .or, and .and Because a method on a reactive value always returns another reactive value, and because only nil and false are false in ruby, we need a way to check if a ReactiveValue is truthy in our code. The easiest way to do this is by calling .true? on it. It will return a non-wrapped boolean. .nil? and .false? do as you would expect. One common place we use a truthy check is in setting up default values with || (logical or) Volt provides a convience method that does the same thing .or, but works with ReactiveValue's. Instead of ```ruby a || b ``` Simply use: ```ruby a.or(b) ``` .and works the same way as &&. #and and #or let you maintain the reactivity all of the way through. ### With ... TODO: ... ## Bindings Now that you understand the basics of ReactiveValue's, we can discuss bindings. In Volt, you code your views in a handlebar's like template language. Volt provides severial bindings, which handle rendering of something for you. Content bindings are anything inbetween { and } ### Content binding The most basic binding is a content binding:
{some_method}
The content binding runs the ruby code between { and }, then renders the return value. If the returned value is a ReactiveValue, it will update the value updated whenever a 'changed' event is called. ### If binding An if binding lets you provide basic flow control. {#if _some_check?}
render this
{/} Blocks are closed with a {/} When the #if binding is rendered, it will run the ruby code after #if. If the code is true it will render the code below. Again, if the returned value is reactive, it will update as that value changes. If bindings can also have #elsif and #else blocks. {#if _condition_1?}condition 1 true
{#elsif _condition_2?}condition 2 true
{#else}neither true
{/} ### Each binding For iteration over objects, the each binding is provided. {#each _items as item}{item}
{/} Above, if _items was an array, the block would be rendered for each item, setting 'item' to the value of the array element. You can also access the position of the item in the array with the #index method. {#each _items as item}{index}. {item}
{/} For the array: ['one', 'two', 'three'] this would print: 0. one 1. two 2. three You can do {index + 1} to correct the numbers. When items are removed or added to the array, the #each binding automatically and intellegently add or removes the items from/to the dom. ## Attribute Bindings Bindings can also be placed inside of attributes.Text
There are some special features provided to make for elements work as "two way bindings" In the example above, if _name changes, the field will update and if the field is updated, _name will be changed. If the value of a checked attribute is true, the checkbox will be shown checked. If it is checked/unchecked, the value will be updated to true or false. -- TODO: select boxes If you have a controller at app/home/controller/index_controller.rb, and a view at app/home/views/index/index.html, all methods called are called on the controller. # Models Volt's concept of a model is slightly different from many frameworks where a model is the name for the ORM to the database. In Volt a model is a class where you can store data easily. Where that data stored is not the concern of the model, but the class that created the model. Lets first see how to use a model. Volt comes with many built-in models, one is called 'page'. If you call #page on a controller, you will get access to the model. Models provided by Volt are automatically wrapped in a ReactiveValue. ```ruby page._name = 'Ryan' page._name # => @'Ryan' ``` Models act like a hash that you can access with getters and setters that start with an _ Prefixing with an underscore makes sure we don't accidentally try to call a method that doesn't exist and get back nil. There is no need to define which fields a model has, they act similar to a hash, but with a shorter access and assign syntax. Models also let you nest data: ```ruby page._settings._color = 'blue' page._settings._color # => @'blue' page._settings # => @#