Module: Volt

Includes:
Configurations, Modes
Defined in:
lib/volt/controllers/actions.rb,
lib/volt.rb,
lib/volt/cli.rb,
lib/volt/boot.rb,
lib/volt/config.rb,
lib/volt/config.rb,
lib/volt/server.rb,
lib/volt/version.rb,
lib/volt/volt/app.rb,
lib/volt/page/page.rb,
lib/volt/cli/runner.rb,
lib/volt/models/url.rb,
lib/volt/page/tasks.rb,
lib/volt/spec/setup.rb,
lib/volt/volt/users.rb,
app/volt/models/user.rb,
lib/volt/cli/console.rb,
lib/volt/utils/ejson.rb,
lib/volt/utils/modes.rb,
lib/volt/models/dirty.rb,
lib/volt/models/model.rb,
lib/volt/page/channel.rb,
lib/volt/utils/timers.rb,
lib/volt/models/buffer.rb,
lib/volt/models/cursor.rb,
lib/volt/models/errors.rb,
lib/volt/page/document.rb,
lib/volt/router/routes.rb,
lib/volt/spec/capybara.rb,
lib/volt/utils/parsing.rb,
lib/volt/spec/sauce_labs.rb,
lib/volt/data_stores/base.rb,
lib/volt/page/sub_context.rb,
lib/volt/page/url_tracker.rb,
lib/volt/tasks/dispatcher.rb,
lib/volt/volt/environment.rb,
lib/volt/cli/asset_compile.rb,
lib/volt/extra_core/logger.rb,
lib/volt/page/channel_stub.rb,
lib/volt/models/array_model.rb,
lib/volt/models/permissions.rb,
lib/volt/models/validations.rb,
lib/volt/reactive/eventable.rb,
lib/volt/tasks/task_handler.rb,
lib/volt/utils/generic_pool.rb,
lib/volt/models/associations.rb,
lib/volt/reactive/dependency.rb,
lib/volt/utils/event_counter.rb,
lib/volt/utils/local_storage.rb,
lib/volt/utils/local_storage.rb,
lib/volt/models/model_helpers.rb,
lib/volt/models/model_wrapper.rb,
lib/volt/models/state_helpers.rb,
lib/volt/models/state_manager.rb,
lib/volt/page/document_events.rb,
lib/volt/reactive/computation.rb,
lib/volt/server/forking_server.rb,
lib/volt/data_stores/data_store.rb,
lib/volt/models/persistors/base.rb,
lib/volt/page/template_renderer.rb,
lib/volt/reactive/reactive_hash.rb,
lib/volt/server/rack/opal_files.rb,
lib/volt/models/listener_tracker.rb,
lib/volt/models/persistors/flash.rb,
lib/volt/models/persistors/store.rb,
lib/volt/page/targets/dom_target.rb,
lib/volt/reactive/reactive_array.rb,
lib/volt/server/rack/asset_files.rb,
lib/volt/server/rack/index_files.rb,
lib/volt/data_stores/mongo_driver.rb,
lib/volt/models/persistors/params.rb,
lib/volt/page/bindings/if_binding.rb,
lib/volt/page/targets/dom_section.rb,
lib/volt/reactive/class_eventable.rb,
lib/volt/reactive/hash_dependency.rb,
lib/volt/server/component_handler.rb,
lib/volt/server/rack/http_request.rb,
lib/volt/models/persistors/cookies.rb,
lib/volt/page/path_string_renderer.rb,
lib/volt/page/targets/base_section.rb,
lib/volt/page/targets/dom_template.rb,
lib/volt/server/rack/http_resource.rb,
lib/volt/utils/logging/task_logger.rb,
lib/volt/page/bindings/base_binding.rb,
lib/volt/page/bindings/each_binding.rb,
lib/volt/page/bindings/view_binding.rb,
lib/volt/server/component_templates.rb,
lib/volt/server/rack/component_code.rb,
lib/volt/controllers/http_controller.rb,
lib/volt/models/model_hash_behaviour.rb,
lib/volt/page/bindings/event_binding.rb,
lib/volt/page/bindings/yield_binding.rb,
lib/volt/reactive/reactive_accessors.rb,
lib/volt/server/rack/component_paths.rb,
lib/volt/utils/generic_counting_pool.rb,
lib/volt/controllers/model_controller.rb,
lib/volt/extra_core/inflector/methods.rb,
lib/volt/models/persistors/array_store.rb,
lib/volt/models/persistors/local_store.rb,
lib/volt/models/persistors/model_store.rb,
lib/volt/models/persistors/store_state.rb,
lib/volt/page/bindings/content_binding.rb,
lib/volt/page/string_template_renderer.rb,
lib/volt/page/targets/attribute_target.rb,
lib/volt/server/html_parser/each_scope.rb,
lib/volt/server/html_parser/view_scope.rb,
lib/volt/server/rack/source_map_server.rb,
app/volt/controllers/notices_controller.rb,
lib/volt/page/targets/attribute_section.rb,
lib/volt/server/html_parser/view_parser.rb,
lib/volt/models/persistors/store_factory.rb,
lib/volt/page/bindings/attribute_binding.rb,
lib/volt/page/bindings/component_binding.rb,
lib/volt/server/html_parser/view_handler.rb,
lib/volt/extra_core/inflector/inflections.rb,
lib/volt/server/html_parser/if_view_scope.rb,
lib/volt/server/rack/http_response_header.rb,
lib/volt/server/socket_connection_handler.rb,
lib/volt/models/validators/email_validator.rb,
lib/volt/models/validators/user_validation.rb,
lib/volt/server/html_parser/textarea_scope.rb,
lib/volt/models/persistors/query/normalizer.rb,
lib/volt/models/validators/format_validator.rb,
lib/volt/models/validators/length_validator.rb,
lib/volt/models/validators/unique_validator.rb,
lib/volt/server/html_parser/attribute_scope.rb,
lib/volt/server/rack/http_response_renderer.rb,
lib/volt/server/websocket/websocket_handler.rb,
lib/volt/models/persistors/model_identity_map.rb,
lib/volt/models/validators/presence_validator.rb,
lib/volt/server/html_parser/sandlebars_parser.rb,
lib/volt/server/websocket/rack_server_adaptor.rb,
lib/volt/server/socket_connection_handler_stub.rb,
lib/volt/models/persistors/query/query_listener.rb,
lib/volt/page/targets/helpers/comment_searchers.rb,
lib/volt/page/targets/binding_document/base_node.rb,
lib/volt/page/targets/binding_document/html_node.rb,
lib/volt/server/html_parser/component_view_scope.rb,
lib/volt/models/validators/numericality_validator.rb,
lib/volt/models/validators/phone_number_validator.rb,
lib/volt/models/persistors/query/query_listener_pool.rb,
lib/volt/page/targets/binding_document/component_node.rb,
lib/volt/page/bindings/view_binding/controller_handler.rb,
lib/volt/page/bindings/view_binding/grouped_controllers.rb,
lib/volt/page/bindings/view_binding/view_lookup_for_path.rb

Overview

Some template bindings share the controller with other template bindings based on a name. This class creates a cache based on the group_controller name and the controller class.

Defined Under Namespace

Modules: Actions, Associations, AttributeScope, Buffer, ClassEventable, CommentSearchers, Dirty, Eventable, Inflector, ListenerTracker, LocalStorage, ModelHashBehaviour, ModelHelpers, ModelWrapper, Modes, Parsing, Persistors, Query, ReactiveAccessors, StateHelpers, StateManager, UserValidatorHelpers, Validations, Version Classes: App, ArrayModel, AssetFiles, AttributeBinding, AttributeSection, AttributeTarget, BaseBinding, BaseNode, BaseSection, CLI, Channel, ChannelStub, ComponentBinding, ComponentCode, ComponentHandler, ComponentNode, ComponentPaths, ComponentTemplates, ComponentViewScope, Computation, Console, ContentBinding, ControllerHandler, Cursor, DataStore, Dependency, Dispatcher, Document, DocumentEvents, DomSection, DomTarget, DomTemplate, EJson, EachBinding, EachScope, EmailValidator, Environment, Errors, EventBinding, EventCounter, ForkingServer, FormatValidator, GenericCountingPool, GenericPool, GenericPoolDeleteException, GroupedControllers, HTMLParseError, HashDependency, HtmlNode, HttpController, HttpRequest, HttpResource, HttpResponseHeader, HttpResponseRenderer, IfBinding, IfViewScope, IndexFiles, InvalidFieldName, JSEvent, LengthValidator, Listener, Model, ModelController, ModelIdentityMap, NilMethodCall, NoticesController, NumericalityValidator, OpalFiles, Page, PathStringRenderer, PhoneNumberValidator, PresenceValidator, QueryListener, QueryListenerPool, RackServerAdaptor, ReactiveArray, ReactiveHash, Routes, SandlebarsParser, Server, SocketConnectionHandler, SocketConnectionHandlerStub, SourceMapServer, StringTemplateRenderer, SubContext, Task, TaskLogger, Tasks, TemplateRenderer, TextareaScope, Timers, URL, UniqueValidator, UrlTracker, User, ViewBinding, ViewHandler, ViewLookupException, ViewLookupForPath, ViewParser, ViewScope, VoltLogger, VoltLoggerFormatter, WebsocketHandler, YieldBinding

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from Modes

included

Class Attribute Details

.loggerObject



50
51
52
# File 'lib/volt.rb', line 50

def logger
  @logger ||= Volt::VoltLogger.new
end

.rootObject



25
26
27
28
29
30
# File 'lib/volt.rb', line 25

def root
  if self.client?
    raise "Volt.root can not be called from the client."
  end
  @root ||= File.expand_path(Dir.pwd)
end

Class Method Details

.as_user(user_id) ⇒ Object

as_user lets you run a block as another user

Parameters:

  • user_id (Integer)


39
40
41
42
43
44
45
46
# File 'lib/volt/volt/users.rb', line 39

def as_user(user_id)
  previous_id = Thread.current['with_user_id']
  Thread.current['with_user_id'] = user_id

  yield

  Thread.current['with_user_id'] = previous_id
end

.boot(app_path) ⇒ Object



20
21
22
23
# File 'lib/volt/boot.rb', line 20

def self.boot(app_path)
  # Boot the app
  App.new(app_path)
end

.client?Boolean

Returns:



38
39
40
# File 'lib/volt.rb', line 38

def client?
  !ENV['SERVER']
end

.current_userObject

Return the current user.



60
61
62
63
# File 'lib/volt/volt/users.rb', line 60

def current_user
  # Run first on the query, or return nil
  user_query.try(:first)
end

.current_user?Boolean

True if the user is logged in and the user is loaded

Returns:



55
56
57
# File 'lib/volt/volt/users.rb', line 55

def current_user?
  !!current_user
end

.current_user_idObject

Get the user_id from the cookie



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/volt/volt/users.rb', line 6

def current_user_id
  # Check for a user_id from with_user
  if (user_id = Thread.current['with_user_id'])
    return user_id
  end

  user_id_signature = self.user_id_signature

  if user_id_signature.nil?
    nil
  else
    index = user_id_signature.index(':')
    user_id = user_id_signature[0...index]

    if RUBY_PLATFORM != 'opal'
      hash = user_id_signature[(index + 1)..-1]

      # Make sure the user hash matches
      # TODO: We could cache the digest generation for even faster comparisons
      if hash != Digest::SHA256.hexdigest("#{Volt.config.app_secret}::#{user_id}")
        # user id has been tampered with, reject
        fail VoltUserError, 'user id or hash is incorrectly signed.  It may have been tampered with, the app secret changed, or generated in a different app.'
      end

    end

    user_id
  end
end

.defaultsObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/volt/config.rb', line 47

def defaults
  app_name = File.basename(Dir.pwd)
  {
    app_name:  app_name,
    db_name:   (ENV['DB_NAME'] || (app_name + '_' + Volt.env.to_s)).gsub('.', '_'),
    db_host:   ENV['DB_HOST'] || 'localhost',
    db_port:   (ENV['DB_PORT'] || 27_017).to_i,
    db_driver: ENV['DB_DRIVER'] || 'mongo',

    # a list of components which should be included in all components
    default_components: ['volt'],

    compress_javascript: Volt.env.production?,
    compress_css:        Volt.env.production?
  }
end

.envObject



46
47
48
# File 'lib/volt.rb', line 46

def env
  @env ||= Volt::Environment.new
end

.fetch_current_userObject



71
72
73
74
75
76
77
78
79
# File 'lib/volt/volt/users.rb', line 71

def fetch_current_user
  u_query = user_query
  if u_query
    u_query.fetch_first
  else
    # No user, resolve nil
    Promise.new.resolve(nil)
  end
end

.in_browser?Boolean

Returns:



56
57
58
# File 'lib/volt.rb', line 56

def in_browser?
  @in_browser
end

.login(username, password) ⇒ Object

Login the user, return a promise for success



82
83
84
85
86
87
88
89
90
# File 'lib/volt/volt/users.rb', line 82

def (username, password)
  UserTasks.({login: username, password: password}).then do |result|
    # Assign the user_id cookie for the user
    $page.cookies._user_id = result

    # Pass nil back
    nil
  end
end

.logoutObject



92
93
94
# File 'lib/volt/volt/users.rb', line 92

def logout
  $page.cookies.delete(:user_id)
end

.reset_config!Object

Resets the configuration to the default (empty hash)



65
66
67
68
69
# File 'lib/volt/config.rb', line 65

def reset_config!
  configure do |c|
    c.from_h(defaults)
  end
end

.run_app_and_initializersObject

Load in all .rb files in the config folder



72
73
74
75
76
77
78
79
# File 'lib/volt/config.rb', line 72

def run_app_and_initializers
  files = ["#{Volt.root}/config/app.rb"]
  files += Dir[Volt.root + '/config/initializers/*.rb']

  files.each do |config_file|
    require(config_file)
  end
end

.server?Boolean

Returns:



34
35
36
# File 'lib/volt.rb', line 34

def server?
  !!ENV['SERVER']
end

.setup_capybara(app_path, volt_app = nil) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/volt/spec/capybara.rb', line 5

def setup_capybara(app_path, volt_app=nil)
  browser = ENV['BROWSER']

  if browser
    setup_capybara_app(app_path, volt_app)

    case browser
    when 'phantom'
      Capybara.default_driver = :poltergeist
    when 'chrome', 'safari'
      # Use the browser name, note that safari requires an extension to run
      browser = browser.to_sym
      Capybara.register_driver(browser) do |app|
        Capybara::Selenium::Driver.new(app, browser: browser)
      end

      Capybara.default_driver = browser
    when 'firefox'
      Capybara.default_driver = :selenium
    when 'sauce'
      setup_sauce_labs
    end
  end
end

.setup_capybara_app(app_path, volt_app) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/volt/spec/capybara.rb', line 30

def setup_capybara_app(app_path, volt_app)
  require 'capybara'
  require 'capybara/dsl'
  require 'capybara/rspec'
  require 'capybara/poltergeist'
  require 'selenium-webdriver'
  require 'volt/server'

  case RUNNING_SERVER
  when 'thin'
    Capybara.server do |app, port|
      require 'rack/handler/thin'
      Rack::Handler::Thin.run(app, Port: port)
    end
  when 'puma'
    Capybara.server do |app, port|
      Puma::Server.new(app).tap do |s|
        s.add_tcp_listener Capybara.server_host, port
      end.run.join
    end
  end

  # Setup server, use existing booted app
  Capybara.app = Server.new(app_path, volt_app).app
end

.setup_client_config(config_hash) ⇒ Object

Called on page load to pass the backend config to the client



19
20
21
22
# File 'lib/volt/config.rb', line 19

def setup_client_config(config_hash)
  # Only Volt.config.public is passed from the server (for security reasons)
  @config = wrap_config(public: config_hash)
end

.setup_sauce_labsObject



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/volt/spec/sauce_labs.rb', line 3

def setup_sauce_labs
  require 'sauce'
  require 'sauce/capybara'

  Sauce.config do |c|
    if ENV['OS']
      # Use a specifc OS, BROWSER, VERSION combo (for travis)
      c[:browsers] = [
        [ENV['OS'], ENV['USE_BROWSER'], ENV['VERSION']]
      ]
    else
      # Run all
      c[:browsers] = [
        # ["Windows 7", "Chrome", "30"],
        # ["Windows 8", "Firefox", "28"],
        ['Windows 8.1', 'Internet Explorer', '11'],
        ['Windows 8.0', 'Internet Explorer', '10'],
        ['Windows 7.0', 'Internet Explorer', '9'],
        # ["OSX 10.9", "iPhone", "8.1"],
        # ["OSX 10.8", "Safari", "6"],
        # ["Linux", "Chrome", "26"]
      ]
    end
    c[:start_local_application] = false
  end

  Capybara.default_driver = :sauce
  Capybara.javascript_driver = :sauce
end

.skip_permissionsObject



48
49
50
51
52
# File 'lib/volt/volt/users.rb', line 48

def skip_permissions
  Volt.run_in_mode(:skip_permissions) do
    yield
  end
end

.source_maps?Boolean

Returns:



42
43
44
# File 'lib/volt.rb', line 42

def source_maps?
  !!ENV['MAPS']
end

.spec_setup(app_path = '.') ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/volt/spec/setup.rb', line 7

def spec_setup(app_path = '.')
  require 'volt'

  ENV['SERVER'] = 'true'
  ENV['VOLT_ENV'] = 'test'

  require 'volt/boot'

  # Require in app
  volt_app = Volt.boot(app_path)

  unless RUBY_PLATFORM == 'opal'
    begin
      require 'volt/spec/capybara'

      setup_capybara(app_path, volt_app)
    rescue LoadError => e
      Volt.logger.warn("unable to load capybara, if you wish to use it for tests, be sure it is in the app's Gemfile")
      Volt.logger.error(e)
    end
  end

  unless ENV['BROWSER']
    # Not running integration tests with ENV['BROWSER']
    RSpec.configuration.filter_run_excluding :type => :feature
  end

  # Setup the spec collection accessors
  # RSpec.shared_context "volt collections", {} do
  RSpec.shared_examples_for 'volt collections', {} do
    # Page conflicts with capybara's page method, so we call it the_page for now.
    # TODO: we need a better solution for page

    let(:the_page) { Model.new }
    let(:store) do
      @__store_accessed = true
      $page ||= Page.new
      $page.store
    end

    after do
      if @__store_accessed
        # Clear the database after each spec where we use store
        # @@db ||= Volt::DataStore.fetch
        # @@db.drop_database
        Volt::DataStore.fetch.drop_database

        $page.instance_variable_set('@store', nil)
      end
    end
  end

end

.userObject

Put in a deprecation placeholder



66
67
68
69
# File 'lib/volt/volt/users.rb', line 66

def user
  Volt.logger.warn("deprication: Volt.user has been renamed to Volt.current_user (to be more clear about what it returns).  Volt.user will be deprecated in the future.")
  current_user
end

.user_id_signatureObject

Fetches the user_id+signature from the correct spot depending on client or server, does not verify it.



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/volt/volt/users.rb', line 98

def user_id_signature
  if Volt.client?
    user_id_signature = $page.cookies._user_id
  else
    # Check meta for the user id and validate it
     = Thread.current['meta']
    if 
      user_id_signature = ['user_id']
    else
      user_id_signature = nil
    end
  end

  user_id_signature
end

.wrap_config(hash) ⇒ Object

Wraps the config hash in an OpenStruct so it can be accessed in the same way as the server side config.



26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/volt/config.rb', line 26

def wrap_config(hash)
  new_hash = {}

  hash.each_pair do |key, value|
    if value.is_a?(Hash)
      new_hash[key] = wrap_config(value)
    else
      new_hash[key] = value
    end
  end

  OpenStruct.new(new_hash)
end