rbjs 0.9.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/Rakefile +1 -0
- data/lib/rbjs.rb +142 -0
- data/lib/rbjs/setup_action_controller.rb +13 -0
- data/lib/rbjs/setup_action_view.rb +25 -0
- data/lib/rbjs/version.rb +3 -0
- data/rbjs.gemspec +26 -0
- data/readme.md +88 -0
- metadata +96 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (2011) Stefan Buhrmester
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/rbjs.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require "rbjs/version"
|
2
|
+
require 'rails'
|
3
|
+
require 'active_support'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Rbjs
|
7
|
+
|
8
|
+
class Railtie < Rails::Railtie
|
9
|
+
initializer 'rbjs.setup' do
|
10
|
+
ActiveSupport.on_load(:action_controller) do
|
11
|
+
require 'rbjs/setup_action_controller'
|
12
|
+
end
|
13
|
+
ActiveSupport.on_load(:action_view) do
|
14
|
+
require 'rbjs/setup_action_view'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Root
|
20
|
+
def initialize view_context, &block
|
21
|
+
@_view_context = view_context and
|
22
|
+
for instance_var, val in view_context.assigns
|
23
|
+
instance_variable_set '@'+instance_var, val
|
24
|
+
end
|
25
|
+
if @_view_context.respond_to?(:helpers) && @_view_context.helpers
|
26
|
+
extend @_view_context.helpers
|
27
|
+
end
|
28
|
+
@_block = block
|
29
|
+
@_called_statements = []
|
30
|
+
end
|
31
|
+
|
32
|
+
def evaluate function_parameters = nil
|
33
|
+
instance_exec *function_parameters, &@_block
|
34
|
+
@_called_statements.map(&:last_of_chain).reject(&:is_argument).map(&:to_s).join(";\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing name, *args, &block
|
38
|
+
if @_view_context and @_view_context.respond_to?(name)
|
39
|
+
@_view_context.send name, *args, &block
|
40
|
+
else
|
41
|
+
statement = Statement.new name, @_view_context, *args, &block
|
42
|
+
@_called_statements << statement
|
43
|
+
statement
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def << line
|
48
|
+
@_called_statements << Statement.new(line)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Statement
|
53
|
+
attr_accessor :parent_statement
|
54
|
+
attr_accessor :child_statement
|
55
|
+
attr_accessor :is_argument
|
56
|
+
|
57
|
+
def initialize name, view_context, *args, &block
|
58
|
+
@name = name.to_s.gsub '!', '()'
|
59
|
+
@_view_context = view_context
|
60
|
+
args << block if block_given?
|
61
|
+
@arguments = args.map{|arg| to_argument(arg)}
|
62
|
+
end
|
63
|
+
|
64
|
+
def method_missing name, *args, &block
|
65
|
+
statement = Statement.new name, @_view_context, *args, &block
|
66
|
+
statement.parent_statement = self
|
67
|
+
self.child_statement = statement
|
68
|
+
statement
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_s
|
72
|
+
if ['+','-','*','/'].include?(@name)
|
73
|
+
@parent_statement.to_s + @name + @arguments.first
|
74
|
+
elsif @name == '[]='
|
75
|
+
@parent_statement.to_s + '[' + @arguments.first + ']= ' + @arguments.last
|
76
|
+
elsif @name == '[]'
|
77
|
+
@parent_statement.to_s + '[' + @arguments.first + ']'
|
78
|
+
elsif @parent_statement
|
79
|
+
@parent_statement.to_s + '.' + @name + argument_list
|
80
|
+
else
|
81
|
+
@name + argument_list
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def argument_list
|
86
|
+
return '' if @arguments.empty?
|
87
|
+
|
88
|
+
'(' + @arguments.join(', ') + ')'
|
89
|
+
end
|
90
|
+
|
91
|
+
def last_of_chain
|
92
|
+
if @child_statement
|
93
|
+
@child_statement.last_of_chain
|
94
|
+
else
|
95
|
+
self
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_argument arg
|
100
|
+
if arg.is_a?(Statement)
|
101
|
+
arg.is_argument = true
|
102
|
+
arg.to_s
|
103
|
+
elsif arg.is_a?(ArgumentProxy)
|
104
|
+
arg.to_s
|
105
|
+
elsif arg.is_a?(Array)
|
106
|
+
'['+arg.map{|val|to_argument(val)}.join(', ')+']'
|
107
|
+
elsif arg.is_a?(Hash)
|
108
|
+
'{'+arg.map{|key, val|to_argument(key)+': '+to_argument(val)}.join(',')+'}'
|
109
|
+
elsif arg.is_a?(Proc)
|
110
|
+
begin
|
111
|
+
root = Root.new(@_view_context, &arg)
|
112
|
+
function_parameters = []
|
113
|
+
function_parameter_names = []
|
114
|
+
for param in arg.parameters
|
115
|
+
function_parameter_names << param[1]
|
116
|
+
function_parameters << ArgumentProxy.new(root, param[1])
|
117
|
+
end
|
118
|
+
"function(#{function_parameter_names.join ', '}) {\n#{root.evaluate function_parameters}}"
|
119
|
+
end
|
120
|
+
else
|
121
|
+
arg.to_json
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class ArgumentProxy
|
127
|
+
def initialize root, name
|
128
|
+
@root = root
|
129
|
+
@name = name
|
130
|
+
end
|
131
|
+
|
132
|
+
def method_missing name, *args, &block
|
133
|
+
statement = @root.send(@name)
|
134
|
+
statement.send name, *args, &block
|
135
|
+
end
|
136
|
+
|
137
|
+
def to_s
|
138
|
+
@name
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Rbjs
|
2
|
+
module ControllerExtensions
|
3
|
+
def render *args, &block
|
4
|
+
if args.first == :js
|
5
|
+
self.content_type = Mime::JS
|
6
|
+
self.response_body = Rbjs::Root.new(view_context, &block).evaluate
|
7
|
+
else
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
ActionController::Base.send :include, ControllerExtensions
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
ActionView::Helpers::RenderingHelper.module_eval do
|
3
|
+
def render_with_js(options = {}, locals = {}, &block)
|
4
|
+
if options == :js
|
5
|
+
Rbjs::Root.new(self, &block).evaluate
|
6
|
+
else
|
7
|
+
render_without_js(options, locals, &block)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
alias_method_chain :render, :js
|
11
|
+
end
|
12
|
+
|
13
|
+
module Rbjs
|
14
|
+
class TemplateHandler
|
15
|
+
|
16
|
+
class_attribute :default_format
|
17
|
+
self.default_format = Mime::JS
|
18
|
+
|
19
|
+
def call(template)
|
20
|
+
"Rbjs::Root.new self do\n#{template.source}\nend.evaluate"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
ActionView::Template.register_template_handler :rbjs, Rbjs::TemplateHandler.new
|
data/lib/rbjs/version.rb
ADDED
data/rbjs.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rbjs/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rbjs"
|
7
|
+
s.version = Rbjs::VERSION
|
8
|
+
s.authors = ["Stefan Buhrmester"]
|
9
|
+
s.email = ["buhrmi@gmail.com"]
|
10
|
+
s.homepage = "http://buhrmi.github.com/rbjs"
|
11
|
+
s.summary = "Remote Javascript re-imagined"
|
12
|
+
s.description = "Remote Javascript Builder for Ruby on Rails"
|
13
|
+
|
14
|
+
s.rubyforge_project = "rbjs"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
s.add_runtime_dependency "json"
|
24
|
+
s.add_runtime_dependency "rails"
|
25
|
+
s.add_runtime_dependency "activesupport"
|
26
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# RJS IS BACK
|
2
|
+
|
3
|
+
## And it's better than ever before.
|
4
|
+
|
5
|
+
Rbjs is a modern RJS extension for Rails 3 and up. It stands for **r**u**b**y**j**ava**s**cript. In contrast to prototype-rails, this library is designed to work with all javascript frameworks.
|
6
|
+
|
7
|
+
However, it is *not* a drop-in replacement for _.rjs_. It does things quite differently.
|
8
|
+
|
9
|
+
### Take a look at a simple example:
|
10
|
+
|
11
|
+
# controllers/greeter_controller.rb
|
12
|
+
def greet_me
|
13
|
+
render :js do
|
14
|
+
window.alert "Hello, #{current_user_name}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# views/greeter/index.html.erb
|
19
|
+
link_to "Hi there!", "greeter#greet_me", :remote => true
|
20
|
+
|
21
|
+
### And a more complex example:
|
22
|
+
|
23
|
+
# controllers/posts_controller.rb
|
24
|
+
def refresh
|
25
|
+
post = Post.find params[:id]
|
26
|
+
render :js do
|
27
|
+
post_element = jQuery(post.selector)
|
28
|
+
post_element.html(render post)
|
29
|
+
post_element.css(:opacity => 0).animate(:opacity => 1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# views/posts/index.html.erb
|
34
|
+
link_to "Refresh Post", refresh_post_path(post), :remote => true
|
35
|
+
|
36
|
+
### You can also create .rbjs templates:
|
37
|
+
|
38
|
+
# controllers/posts_controller.rb
|
39
|
+
def refresh_all
|
40
|
+
@posts = Post.all.limit(10)
|
41
|
+
end
|
42
|
+
|
43
|
+
# views/posts/refresh_all.js.rbjs
|
44
|
+
for post in @posts
|
45
|
+
jQuery(post.selector).html(render post)
|
46
|
+
end
|
47
|
+
|
48
|
+
### Do complex stuff:
|
49
|
+
|
50
|
+
# controllers/posts_controller.rb
|
51
|
+
def increase_counter
|
52
|
+
@increment = 4
|
53
|
+
end
|
54
|
+
|
55
|
+
# views/posts/increase_counter.js.rbjs
|
56
|
+
allCounters = jQuery('.post.counter')
|
57
|
+
allCounters.each do |index, element|
|
58
|
+
element = jQuery(element)
|
59
|
+
currentValue = element.html!.to_i!
|
60
|
+
element.html(currentValue + @increment)
|
61
|
+
end
|
62
|
+
|
63
|
+
# And the rendered result. Note the behavior of local variables.
|
64
|
+
jQuery(".post.counter").each(
|
65
|
+
function(index, element) {
|
66
|
+
jQuery(element).html(jQuery(element).html().to_i()+4)
|
67
|
+
}
|
68
|
+
)
|
69
|
+
|
70
|
+
|
71
|
+
# Here is the same example, but with variables assigned to javascript instead of local ruby variables.
|
72
|
+
# views/posts/increase_counter.js.rbjs
|
73
|
+
self.allCounters = jQuery('.post.counter')
|
74
|
+
self.allCounters.each do |index, element|
|
75
|
+
self.element = jQuery(element)
|
76
|
+
self.currentValue = element.html!.to_i!
|
77
|
+
element.html(currentValue + @increment)
|
78
|
+
end
|
79
|
+
|
80
|
+
# And the rendered result:
|
81
|
+
allCounters=(jQuery(".post.counter"));
|
82
|
+
allCounters.each(function(index, element) {
|
83
|
+
element=(jQuery(element));
|
84
|
+
currentValue=(element.html().to_i());
|
85
|
+
element.html(currentValue+4)
|
86
|
+
})
|
87
|
+
|
88
|
+
More to come.
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rbjs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.9.7
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Stefan Buhrmester
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-11-03 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: json
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rails
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: activesupport
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id003
|
48
|
+
description: Remote Javascript Builder for Ruby on Rails
|
49
|
+
email:
|
50
|
+
- buhrmi@gmail.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- Gemfile
|
60
|
+
- LICENSE
|
61
|
+
- Rakefile
|
62
|
+
- lib/rbjs.rb
|
63
|
+
- lib/rbjs/setup_action_controller.rb
|
64
|
+
- lib/rbjs/setup_action_view.rb
|
65
|
+
- lib/rbjs/version.rb
|
66
|
+
- rbjs.gemspec
|
67
|
+
- readme.md
|
68
|
+
homepage: http://buhrmi.github.com/rbjs
|
69
|
+
licenses: []
|
70
|
+
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: "0"
|
88
|
+
requirements: []
|
89
|
+
|
90
|
+
rubyforge_project: rbjs
|
91
|
+
rubygems_version: 1.8.11
|
92
|
+
signing_key:
|
93
|
+
specification_version: 3
|
94
|
+
summary: Remote Javascript re-imagined
|
95
|
+
test_files: []
|
96
|
+
|