buttons 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|