buttons 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/LICENSE +20 -0
- data/README.rdoc +74 -0
- data/Rakefile +34 -0
- data/VERSION +1 -0
- data/bin/buttons +7 -0
- data/generators/buttons_app/buttons_app_generator.rb +24 -0
- data/generators/buttons_app/templates/Rakefile +0 -0
- data/generators/buttons_app/templates/app/buttons/example_button.rb +11 -0
- data/generators/buttons_app/templates/config.ru +8 -0
- data/generators/buttons_app/templates/public/index.html +9 -0
- data/generators/buttons_app/templates/start.rb +8 -0
- data/lib/buttons.rb +23 -0
- data/lib/buttons/application.rb +68 -0
- data/lib/buttons/button.rb +119 -0
- data/lib/buttons/config.rb +13 -0
- data/lib/buttons/core_ext/string.rb +9 -0
- data/lib/buttons/javascript.rb +7 -0
- data/lib/buttons/javascript/js_arg.rb +30 -0
- data/lib/buttons/javascript/js_function.rb +62 -0
- data/lib/buttons/javascript/js_generator.rb +27 -0
- data/lib/buttons/javascript/js_var.rb +16 -0
- data/lib/buttons/router.rb +28 -0
- data/public/index.txt +1 -0
- data/tasks/test.rake +6 -0
- data/tests/button_tests.rb +58 -0
- data/tests/helper.rb +3 -0
- data/tests/javascript_tests.rb +86 -0
- metadata +155 -0
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Clinton R. Nixon
|
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/README.rdoc
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
= Buttons
|
2
|
+
|
3
|
+
<b>NOTE: This is a very early version of Buttons. Expect it to change rapidly.</b>
|
4
|
+
|
5
|
+
Buttons is a Rack framework for working with JavaScript-heavy applications. It
|
6
|
+
automatically creates Ajax endpoints for Ruby methods, and creates a set of
|
7
|
+
JavaScript functions to access those endpoints.
|
8
|
+
|
9
|
+
== Example
|
10
|
+
|
11
|
+
Here's an example. The Ruby class below will automatically generate the
|
12
|
+
JavaScript found beneath it. For now, we only generate code that relies on
|
13
|
+
jQuery, but that's planned to change.
|
14
|
+
|
15
|
+
Ruby code:
|
16
|
+
|
17
|
+
class ProfileButton < Buttons::Button
|
18
|
+
get :show
|
19
|
+
post :login
|
20
|
+
|
21
|
+
def login(username, password)
|
22
|
+
# The variable's set just to show that it's being returned.
|
23
|
+
token = generate_login_token(username, password)
|
24
|
+
token
|
25
|
+
end
|
26
|
+
|
27
|
+
def show(profile_id)
|
28
|
+
Profile.find(profile_id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
JavaScript code (found at /profile.js):
|
33
|
+
|
34
|
+
(function () {
|
35
|
+
this.Profile = {};
|
36
|
+
|
37
|
+
Profile.login = function (username, password, _ajaxOptions) {
|
38
|
+
var data = { 'username': username, 'password': password };
|
39
|
+
if (_ajaxOptions === undefined || typeof(_ajaxOptions) != "object") {
|
40
|
+
_ajaxOptions = {};
|
41
|
+
}
|
42
|
+
_ajaxOptions['type'] = "POST";
|
43
|
+
_ajaxOptions['url'] = "/profile/login";
|
44
|
+
_ajaxOptions['data'] = data;
|
45
|
+
|
46
|
+
if (_ajaxOptions['dataType'] === 'undefined') {
|
47
|
+
_ajaxOptions['dataType'] = 'json';
|
48
|
+
}
|
49
|
+
|
50
|
+
return jQuery.ajax(_ajaxOptions);
|
51
|
+
};
|
52
|
+
|
53
|
+
Profile.show = function (profileId, _ajaxOptions) {
|
54
|
+
var data = { 'profile_id': profileId };
|
55
|
+
if (_ajaxOptions === undefined || typeof(_ajaxOptions) != "object") {
|
56
|
+
_ajaxOptions = {};
|
57
|
+
}
|
58
|
+
_ajaxOptions['type'] = "GET";
|
59
|
+
_ajaxOptions['url'] = "/profile/show";
|
60
|
+
_ajaxOptions['data'] = data;
|
61
|
+
|
62
|
+
if (_ajaxOptions['dataType'] === 'undefined') {
|
63
|
+
_ajaxOptions['dataType'] = 'json';
|
64
|
+
}
|
65
|
+
|
66
|
+
return jQuery.ajax(_ajaxOptions);
|
67
|
+
};
|
68
|
+
})();
|
69
|
+
|
70
|
+
== How to use this
|
71
|
+
|
72
|
+
Run <tt>buttons <directory></tt> to create a new Buttons application in that
|
73
|
+
directory. There's not any helpers or generators yet, but you can look at the
|
74
|
+
generated application to figure it out for now.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
task :default => :test
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'jeweler'
|
5
|
+
Jeweler::Tasks.new do |gemspec|
|
6
|
+
gemspec.name = "buttons"
|
7
|
+
gemspec.summary = "Buttons is a Rack framework for working with JavaScript-heavy applications."
|
8
|
+
gemspec.description = "Buttons is a Rack framework for working with JavaScript-heavy applications. It
|
9
|
+
automatically creates Ajax endpoints for Ruby methods, and creates a set of
|
10
|
+
JavaScript functions to access those endpoints."
|
11
|
+
gemspec.email = "crnixon@gmail.com"
|
12
|
+
gemspec.homepage = "http://github.com/crnixon/buttons"
|
13
|
+
gemspec.authors = ["Clinton R. Nixon"]
|
14
|
+
|
15
|
+
gemspec.add_dependency('get_args', '>= 1.1.1')
|
16
|
+
gemspec.add_dependency('facets')
|
17
|
+
gemspec.add_dependency('json')
|
18
|
+
gemspec.add_dependency('rack', '>= 1.0.1')
|
19
|
+
gemspec.add_dependency('bundler')
|
20
|
+
gemspec.add_dependency('rubigen')
|
21
|
+
gemspec.add_development_dependency('riot')
|
22
|
+
|
23
|
+
# if RUBY_PLATFORM != 'java' && RUBY_VERSION < "1.9"
|
24
|
+
# gemspec.add_dependency('ParseTree')
|
25
|
+
# gemspec.add_dependency('ruby2ruby')
|
26
|
+
# end
|
27
|
+
end
|
28
|
+
|
29
|
+
Jeweler::GemcutterTasks.new
|
30
|
+
rescue LoadError
|
31
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
32
|
+
end
|
33
|
+
|
34
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks', '*.rake')].each { |file| load file }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bin/buttons
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rubigen'
|
4
|
+
require 'rubigen/scripts/generate'
|
5
|
+
|
6
|
+
RubiGen::Base.sources << RubiGen::PathSource.new(:buttons, File.join(File.dirname(__FILE__), %w[.. generators]))
|
7
|
+
RubiGen::Scripts::Generate.new.run(ARGV, :generator => 'buttons_app')
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class ButtonsAppGenerator < RubiGen::Base
|
2
|
+
BASEDIRS = ['app', 'app/buttons', 'public']
|
3
|
+
|
4
|
+
def initialize(args, opts = {})
|
5
|
+
super
|
6
|
+
usage if args.empty?
|
7
|
+
@destination_root = args.shift
|
8
|
+
@app_name = File.basename(File.expand_path(@destination_root))
|
9
|
+
@module_name = @app_name.camelize
|
10
|
+
end
|
11
|
+
|
12
|
+
def manifest
|
13
|
+
record do |m|
|
14
|
+
m.directory ''
|
15
|
+
BASEDIRS.each { |dir| m.directory dir }
|
16
|
+
|
17
|
+
m.file_copy_each [ 'config.ru',
|
18
|
+
'start.rb',
|
19
|
+
'Rakefile',
|
20
|
+
'public/index.html',
|
21
|
+
'app/buttons/example_button.rb' ]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
File without changes
|
data/lib/buttons.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'facets'
|
3
|
+
|
4
|
+
module Buttons
|
5
|
+
def self.lib_root(*paths)
|
6
|
+
File.expand_path(File.join(File.dirname(__FILE__), 'buttons', *paths))
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.app(&block)
|
10
|
+
@app ||= Buttons::Application.new
|
11
|
+
@app.instance_eval(&block) unless block.nil?
|
12
|
+
@app
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configure
|
16
|
+
yield app if block_given?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require Buttons.lib_root('core_ext/string')
|
21
|
+
require Buttons.lib_root('application')
|
22
|
+
require Buttons.lib_root('javascript')
|
23
|
+
require Buttons.lib_root('button')
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require Buttons.lib_root('router')
|
2
|
+
require Buttons.lib_root('config')
|
3
|
+
|
4
|
+
module Buttons
|
5
|
+
class Application
|
6
|
+
include Buttons::Config
|
7
|
+
|
8
|
+
def initialize(&block)
|
9
|
+
@router ||= Buttons::Router.new
|
10
|
+
@middlewares ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def use(middleware, options = nil)
|
14
|
+
@middlewares << [middleware, options]
|
15
|
+
end
|
16
|
+
|
17
|
+
def start
|
18
|
+
unless app_root.nil?
|
19
|
+
Dir[app_root('app', '**', '*.rb')].each do |ruby_file|
|
20
|
+
require ruby_file
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_route(http_method, path, params)
|
26
|
+
@router.add_route(http_method, path, params)
|
27
|
+
end
|
28
|
+
|
29
|
+
def call(environment)
|
30
|
+
rack_app = lambda { |env|
|
31
|
+
request = ::Rack::Request.new(env)
|
32
|
+
response = ::Rack::Response.new
|
33
|
+
route = @router.recognize(request)
|
34
|
+
|
35
|
+
if route
|
36
|
+
render(request, response, route)
|
37
|
+
else
|
38
|
+
[404, {"Content-Type" => 'text/plain'}, "not found: #{request.path}\n\n" +
|
39
|
+
"All routes: \n#{@router.print_routes}"
|
40
|
+
]
|
41
|
+
end
|
42
|
+
}
|
43
|
+
|
44
|
+
@middlewares.each do |middleware, options|
|
45
|
+
rack_app = if options
|
46
|
+
middleware.new(rack_app, options)
|
47
|
+
else
|
48
|
+
middleware.new(rack_app)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
rack_app.call environment
|
53
|
+
end
|
54
|
+
|
55
|
+
def render(request, response, params)
|
56
|
+
button_klass, method_name = params[:button], params[:method]
|
57
|
+
|
58
|
+
response['Content-Type'] = 'text/javascript'
|
59
|
+
content = button_klass.new(request).call_method(method_name)
|
60
|
+
if conversion = params.delete(:convert)
|
61
|
+
content = content.send(conversion)
|
62
|
+
end
|
63
|
+
response.write(content)
|
64
|
+
|
65
|
+
response.finish
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'get_args'
|
2
|
+
|
3
|
+
module Buttons
|
4
|
+
class Button
|
5
|
+
attr_reader :request
|
6
|
+
|
7
|
+
def initialize(request)
|
8
|
+
@request = request
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_js
|
12
|
+
self.class.to_js
|
13
|
+
end
|
14
|
+
|
15
|
+
def call_method(method_name)
|
16
|
+
send(method_name, *create_method_args(method_name))
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def inherited(base)
|
21
|
+
Buttons.app.add_route(:get, "/#{base.namespace}.js",
|
22
|
+
:button => base, :method => :to_js)
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_added(name)
|
26
|
+
routes.each do |http_method, methods|
|
27
|
+
if methods.include?(name)
|
28
|
+
setup_route(http_method, instance_method(name))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def namespace
|
34
|
+
self.to_s.debuttonize
|
35
|
+
end
|
36
|
+
|
37
|
+
def js_functions
|
38
|
+
@js_functions ||= []
|
39
|
+
end
|
40
|
+
|
41
|
+
def argument_list
|
42
|
+
@argument_list ||= {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def routes
|
46
|
+
@routes ||= { }
|
47
|
+
end
|
48
|
+
|
49
|
+
def get(*names)
|
50
|
+
names.each do |name|
|
51
|
+
add_route(:get, name)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def post(*names)
|
56
|
+
names.each do |name|
|
57
|
+
add_route(:post, name)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_js
|
62
|
+
Buttons::Javascript::JsGenerator.new(self).to_js
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def add_route(http_method, name)
|
68
|
+
routes[http_method] ||= []
|
69
|
+
routes[http_method] << name
|
70
|
+
|
71
|
+
method = instance_method(name) rescue nil
|
72
|
+
if method
|
73
|
+
setup_route(http_method, method)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def setup_route(http_method, method)
|
78
|
+
name = method.name
|
79
|
+
route_path = "/#{namespace}/#{name}"
|
80
|
+
argument_list[name] = method.get_argument_list
|
81
|
+
js_functions << Buttons::Javascript::JsFunction.new(
|
82
|
+
name, http_method, route_path, method.get_argument_list)
|
83
|
+
Buttons.app.add_route(http_method, route_path,
|
84
|
+
:button => self, :method => name, :convert => 'to_json')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def params
|
91
|
+
request.params
|
92
|
+
end
|
93
|
+
|
94
|
+
def create_method_args(method_name)
|
95
|
+
args = []
|
96
|
+
argument_list = self.class.argument_list[method_name]
|
97
|
+
|
98
|
+
unless argument_list.nil?
|
99
|
+
argument_list.each do |argument|
|
100
|
+
param_name = argument.name.to_s
|
101
|
+
param_name = param_name.slice(1, param_name.length) if argument.multiple?
|
102
|
+
value = params[param_name]
|
103
|
+
|
104
|
+
if value.nil? and argument.optional?
|
105
|
+
value = argument.default
|
106
|
+
end
|
107
|
+
if argument.multiple?
|
108
|
+
args += value
|
109
|
+
else
|
110
|
+
args << value
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
p args.inspect
|
116
|
+
args
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Buttons
|
2
|
+
module Javascript
|
3
|
+
class JsArg < JsVar
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
def initialize(var)
|
7
|
+
@var = var
|
8
|
+
super(@var.name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(*args, &block)
|
12
|
+
@var.send(*args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def default
|
16
|
+
@var.default.to_json
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_default(index)
|
20
|
+
if optional?
|
21
|
+
%Q[
|
22
|
+
if (#{name} === undefined) {
|
23
|
+
#{name} = #{default};
|
24
|
+
}
|
25
|
+
]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Buttons
|
2
|
+
module Javascript
|
3
|
+
class JsFunction < JsVar
|
4
|
+
attr_reader :name, :args
|
5
|
+
|
6
|
+
def initialize(name, http_method, url, args)
|
7
|
+
super(name)
|
8
|
+
|
9
|
+
@http_method = http_method
|
10
|
+
@url = url
|
11
|
+
@args = args.map { |arg| JsArg.new(arg) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_js(namespace = 'this')
|
15
|
+
%Q[
|
16
|
+
#{namespace}.#{name} = function (#{args_to_param_list}, _ajaxOptions) {
|
17
|
+
#{args_to_defaults}
|
18
|
+
#{assign_args_to_js_object}
|
19
|
+
#{ajax_call}
|
20
|
+
};
|
21
|
+
].strip_whitespace
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def ajax_call
|
27
|
+
%Q[
|
28
|
+
if (_ajaxOptions === undefined || typeof(_ajaxOptions) != "object") {
|
29
|
+
_ajaxOptions = {};
|
30
|
+
}
|
31
|
+
_ajaxOptions['type'] = #{@http_method.to_s.upcase.to_json};
|
32
|
+
_ajaxOptions['url'] = #{@url.to_json};
|
33
|
+
_ajaxOptions['data'] = data;
|
34
|
+
|
35
|
+
if (_ajaxOptions['dataType'] === 'undefined') {
|
36
|
+
_ajaxOptions['dataType'] = 'json';
|
37
|
+
}
|
38
|
+
|
39
|
+
return jQuery.ajax(_ajaxOptions);
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
def args_to_param_list
|
44
|
+
args.map { |arg| arg.name }.compact.join(", ")
|
45
|
+
end
|
46
|
+
|
47
|
+
def args_to_defaults
|
48
|
+
args.map_with_index { |arg, i|
|
49
|
+
arg.to_default(i)
|
50
|
+
}.compact.join("\n")
|
51
|
+
end
|
52
|
+
|
53
|
+
def assign_args_to_js_object
|
54
|
+
arg_assignments = args.map { |arg|
|
55
|
+
"'#{arg.ruby_name}#{'[]' if arg.multiple?}': #{arg.name}"
|
56
|
+
}.join(", ")
|
57
|
+
|
58
|
+
%Q[var data = { #{arg_assignments} };]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "yui/compressor"
|
2
|
+
|
3
|
+
module Buttons
|
4
|
+
module Javascript
|
5
|
+
class JsGenerator
|
6
|
+
def initialize(button)
|
7
|
+
@button = button
|
8
|
+
# @compressor = YUI::JavaScriptCompressor.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_js
|
12
|
+
js = %Q[
|
13
|
+
(function () {
|
14
|
+
this.#{@button.namespace.capitalize} = {};
|
15
|
+
|
16
|
+
#{@button.js_functions.map { |function|
|
17
|
+
function.to_js(@button.namespace.capitalize)
|
18
|
+
}.join("\n")}
|
19
|
+
})();
|
20
|
+
]
|
21
|
+
|
22
|
+
# @compressor.compress(js)
|
23
|
+
js.strip_whitespace
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Buttons
|
2
|
+
class Router
|
3
|
+
def initialize
|
4
|
+
@routes = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def add_route(http_method, path, params)
|
8
|
+
http_method = http_method.to_s.downcase
|
9
|
+
|
10
|
+
@routes[http_method] ||= {}
|
11
|
+
@routes[http_method][path] = params
|
12
|
+
end
|
13
|
+
|
14
|
+
def recognize(request)
|
15
|
+
request_method = request.request_method.to_s.downcase
|
16
|
+
|
17
|
+
@routes[request_method] && @routes[request_method][request.path]
|
18
|
+
end
|
19
|
+
|
20
|
+
def print_routes
|
21
|
+
@routes.map do |http_method, routes|
|
22
|
+
routes.map do |route, params|
|
23
|
+
"%8s %s %s" % [http_method.upcase, route, params.inspect]
|
24
|
+
end.join("\n")
|
25
|
+
end.join("\n")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/public/index.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
hi there
|
data/tasks/test.rake
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
class ProfileButton < Buttons::Button
|
4
|
+
get :show
|
5
|
+
post :login
|
6
|
+
|
7
|
+
def login(username, password)
|
8
|
+
# The variable's set just to show that it's being returned.
|
9
|
+
token = generate_login_token(username, password)
|
10
|
+
token
|
11
|
+
end
|
12
|
+
|
13
|
+
def show(profile_id)
|
14
|
+
Profile.find(profile_id)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "ProfileButton" do
|
19
|
+
should("generate JS") {
|
20
|
+
ProfileButton.to_js
|
21
|
+
}.equals(%Q[
|
22
|
+
(function () {
|
23
|
+
this.Profile = {};
|
24
|
+
|
25
|
+
Profile.login = function (username, password, _ajaxOptions) {
|
26
|
+
var data = { 'username': username, 'password': password };
|
27
|
+
if (_ajaxOptions === undefined || typeof(_ajaxOptions) != "object") {
|
28
|
+
_ajaxOptions = {};
|
29
|
+
}
|
30
|
+
_ajaxOptions['type'] = "POST";
|
31
|
+
_ajaxOptions['url'] = "/profile/login";
|
32
|
+
_ajaxOptions['data'] = data;
|
33
|
+
|
34
|
+
if (_ajaxOptions['dataType'] === 'undefined') {
|
35
|
+
_ajaxOptions['dataType'] = 'json';
|
36
|
+
}
|
37
|
+
|
38
|
+
return jQuery.ajax(_ajaxOptions);
|
39
|
+
};
|
40
|
+
|
41
|
+
Profile.show = function (profileId, _ajaxOptions) {
|
42
|
+
var data = { 'profile_id': profileId };
|
43
|
+
if (_ajaxOptions === undefined || typeof(_ajaxOptions) != "object") {
|
44
|
+
_ajaxOptions = {};
|
45
|
+
}
|
46
|
+
_ajaxOptions['type'] = "GET";
|
47
|
+
_ajaxOptions['url'] = "/profile/show";
|
48
|
+
_ajaxOptions['data'] = data;
|
49
|
+
|
50
|
+
if (_ajaxOptions['dataType'] === 'undefined') {
|
51
|
+
_ajaxOptions['dataType'] = 'json';
|
52
|
+
}
|
53
|
+
|
54
|
+
return jQuery.ajax(_ajaxOptions);
|
55
|
+
};
|
56
|
+
})();
|
57
|
+
].strip_whitespace)
|
58
|
+
end
|
data/tests/helper.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
include Buttons::Javascript
|
4
|
+
|
5
|
+
context "a JsVar" do
|
6
|
+
setup { JsVar.new(:remember_me) }
|
7
|
+
|
8
|
+
should("convert underscore syntax to JS syntax") {
|
9
|
+
topic.name
|
10
|
+
}.equals("rememberMe")
|
11
|
+
|
12
|
+
should("remember Ruby name") { topic.ruby_name }.equals("remember_me")
|
13
|
+
|
14
|
+
should("remove leading asterisk") {
|
15
|
+
JsVar.new("*names").name
|
16
|
+
}.equals("names")
|
17
|
+
end
|
18
|
+
|
19
|
+
context "a JsArg" do
|
20
|
+
setup {
|
21
|
+
arg = Struct.new(:name, :default, :optional?, :foo).new(
|
22
|
+
'arg_name', nil, true, :bar)
|
23
|
+
JsArg.new(arg)
|
24
|
+
}
|
25
|
+
|
26
|
+
should("convert default to json") { topic.default }.equals(nil.to_json)
|
27
|
+
|
28
|
+
should("forward all missing methods to arg") { topic.foo }.equals(:bar)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "a JsFunction" do
|
32
|
+
setup {
|
33
|
+
JsFunction.new(:login, :post, '/login', GetArgs::ArgumentList.new(
|
34
|
+
[ [:username], [:password], [:remember_me, true] ]
|
35
|
+
))
|
36
|
+
}
|
37
|
+
|
38
|
+
should("emit JavaScript") {
|
39
|
+
topic.to_js
|
40
|
+
}.equals(
|
41
|
+
%Q[
|
42
|
+
this.login = function (username, password, rememberMe, _ajaxOptions) {
|
43
|
+
if (rememberMe === undefined) { rememberMe = true; }
|
44
|
+
var data = { 'username': username, 'password': password, 'remember_me': rememberMe };
|
45
|
+
if (_ajaxOptions === undefined || typeof(_ajaxOptions) != "object") {
|
46
|
+
_ajaxOptions = {};
|
47
|
+
}
|
48
|
+
_ajaxOptions['type'] = "POST";
|
49
|
+
_ajaxOptions['url'] = "/login";
|
50
|
+
_ajaxOptions['data'] = data;
|
51
|
+
if (_ajaxOptions['dataType'] === 'undefined') {
|
52
|
+
_ajaxOptions['dataType'] = 'json';
|
53
|
+
}
|
54
|
+
return jQuery.ajax(_ajaxOptions);
|
55
|
+
};
|
56
|
+
].strip_whitespace
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
context "a JsFunction with a star argument" do
|
61
|
+
setup {
|
62
|
+
JsFunction.new(:add_users, :post, '/add_users', GetArgs::ArgumentList.new(
|
63
|
+
[ [:admin_username], [:admin_password], ["*new_users"] ]
|
64
|
+
))
|
65
|
+
}
|
66
|
+
|
67
|
+
should("emit JavaScript") {
|
68
|
+
topic.to_js
|
69
|
+
}.equals(
|
70
|
+
%Q[
|
71
|
+
this.addUsers = function (adminUsername, adminPassword, newUsers, _ajaxOptions) {
|
72
|
+
var data = { 'admin_username': adminUsername, 'admin_password': adminPassword, 'new_users[]': newUsers };
|
73
|
+
if (_ajaxOptions === undefined || typeof(_ajaxOptions) != "object") {
|
74
|
+
_ajaxOptions = {};
|
75
|
+
}
|
76
|
+
_ajaxOptions['type'] = "POST";
|
77
|
+
_ajaxOptions['url'] = "/add_users";
|
78
|
+
_ajaxOptions['data'] = data;
|
79
|
+
if (_ajaxOptions['dataType'] === 'undefined') {
|
80
|
+
_ajaxOptions['dataType'] = 'json';
|
81
|
+
}
|
82
|
+
return jQuery.ajax(_ajaxOptions);
|
83
|
+
};
|
84
|
+
].strip_whitespace
|
85
|
+
)
|
86
|
+
end
|
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: buttons
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Clinton R. Nixon
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-13 00:00:00 -05:00
|
13
|
+
default_executable: buttons
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: get_args
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.1.1
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: facets
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: json
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: rack
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.0.1
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: rubigen
|
67
|
+
type: :runtime
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: riot
|
77
|
+
type: :development
|
78
|
+
version_requirement:
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
description: |-
|
86
|
+
Buttons is a Rack framework for working with JavaScript-heavy applications. It
|
87
|
+
automatically creates Ajax endpoints for Ruby methods, and creates a set of
|
88
|
+
JavaScript functions to access those endpoints.
|
89
|
+
email: crnixon@gmail.com
|
90
|
+
executables:
|
91
|
+
- buttons
|
92
|
+
extensions: []
|
93
|
+
|
94
|
+
extra_rdoc_files:
|
95
|
+
- LICENSE
|
96
|
+
- README.rdoc
|
97
|
+
files:
|
98
|
+
- .gitignore
|
99
|
+
- LICENSE
|
100
|
+
- README.rdoc
|
101
|
+
- Rakefile
|
102
|
+
- VERSION
|
103
|
+
- bin/buttons
|
104
|
+
- generators/buttons_app/buttons_app_generator.rb
|
105
|
+
- generators/buttons_app/templates/Rakefile
|
106
|
+
- generators/buttons_app/templates/app/buttons/example_button.rb
|
107
|
+
- generators/buttons_app/templates/config.ru
|
108
|
+
- generators/buttons_app/templates/public/index.html
|
109
|
+
- generators/buttons_app/templates/start.rb
|
110
|
+
- lib/buttons.rb
|
111
|
+
- lib/buttons/application.rb
|
112
|
+
- lib/buttons/button.rb
|
113
|
+
- lib/buttons/config.rb
|
114
|
+
- lib/buttons/core_ext/string.rb
|
115
|
+
- lib/buttons/javascript.rb
|
116
|
+
- lib/buttons/javascript/js_arg.rb
|
117
|
+
- lib/buttons/javascript/js_function.rb
|
118
|
+
- lib/buttons/javascript/js_generator.rb
|
119
|
+
- lib/buttons/javascript/js_var.rb
|
120
|
+
- lib/buttons/router.rb
|
121
|
+
- public/index.txt
|
122
|
+
- tasks/test.rake
|
123
|
+
- tests/button_tests.rb
|
124
|
+
- tests/helper.rb
|
125
|
+
- tests/javascript_tests.rb
|
126
|
+
has_rdoc: true
|
127
|
+
homepage: http://github.com/crnixon/buttons
|
128
|
+
licenses: []
|
129
|
+
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options:
|
132
|
+
- --charset=UTF-8
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: "0"
|
140
|
+
version:
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: "0"
|
146
|
+
version:
|
147
|
+
requirements: []
|
148
|
+
|
149
|
+
rubyforge_project:
|
150
|
+
rubygems_version: 1.3.5
|
151
|
+
signing_key:
|
152
|
+
specification_version: 3
|
153
|
+
summary: Buttons is a Rack framework for working with JavaScript-heavy applications.
|
154
|
+
test_files: []
|
155
|
+
|