bowline 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/History.txt +4 -0
- data/MIT-LICENSE +20 -0
- data/Manifest.txt +58 -0
- data/README.txt +136 -0
- data/Rakefile +25 -0
- data/assets/jquery.bowline.js +96 -0
- data/assets/jquery.chain.js +2348 -0
- data/assets/jquery.js +3549 -0
- data/bin/bowline-gen +6 -0
- data/bowline.gemspec +45 -0
- data/examples/account.rb +31 -0
- data/examples/example.js +24 -0
- data/examples/tweets.rb +28 -0
- data/examples/twitter.html +39 -0
- data/examples/users.rb +37 -0
- data/lib/bowline.rb +42 -0
- data/lib/bowline/binders.rb +177 -0
- data/lib/bowline/binders/collection.rb +27 -0
- data/lib/bowline/binders/singleton.rb +25 -0
- data/lib/bowline/commands/console.rb +27 -0
- data/lib/bowline/commands/generate.rb +1 -0
- data/lib/bowline/commands/run.rb +11 -0
- data/lib/bowline/ext/array.rb +5 -0
- data/lib/bowline/ext/class.rb +51 -0
- data/lib/bowline/ext/object.rb +12 -0
- data/lib/bowline/ext/string.rb +9 -0
- data/lib/bowline/gem_dependency.rb +42 -0
- data/lib/bowline/generators.rb +59 -0
- data/lib/bowline/generators/application.rb +58 -0
- data/lib/bowline/generators/binder.rb +25 -0
- data/lib/bowline/generators/migration.rb +51 -0
- data/lib/bowline/generators/model.rb +20 -0
- data/lib/bowline/initializer.rb +596 -0
- data/lib/bowline/jquery.rb +31 -0
- data/lib/bowline/observer.rb +43 -0
- data/lib/bowline/tasks/app.rake +90 -0
- data/lib/bowline/tasks/bowline.rb +8 -0
- data/lib/bowline/tasks/database.rake +167 -0
- data/lib/bowline/tasks/log.rake +9 -0
- data/lib/bowline/tasks/misk.rake +3 -0
- data/templates/Rakefile +7 -0
- data/templates/binder.rb +9 -0
- data/templates/config/application.yml +1 -0
- data/templates/config/boot.rb +13 -0
- data/templates/config/database.yml +4 -0
- data/templates/config/environment.rb +12 -0
- data/templates/config/manifest +18 -0
- data/templates/config/tiapp.xml +24 -0
- data/templates/gitignore +15 -0
- data/templates/migration.rb +7 -0
- data/templates/model.rb +4 -0
- data/templates/public/index.html +25 -0
- data/templates/public/javascripts/application.js +0 -0
- data/templates/public/stylesheets/application.css +0 -0
- data/templates/script/console +3 -0
- data/templates/script/init +18 -0
- data/templates/script/run +3 -0
- metadata +155 -0
data/bin/bowline-gen
ADDED
data/bowline.gemspec
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{bowline}
|
5
|
+
s.version = "0.1.6"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Alex MacCaw"]
|
9
|
+
s.date = %q{2009-04-24}
|
10
|
+
s.default_executable = %q{bowline-gen}
|
11
|
+
s.description = %q{Ruby desktop application framework}
|
12
|
+
s.email = ["info@eribium.org"]
|
13
|
+
s.executables = ["bowline-gen"]
|
14
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
|
15
|
+
s.files = [".gitignore", "History.txt", "MIT-LICENSE", "Manifest.txt", "README.txt", "Rakefile", "assets/jquery.bowline.js", "assets/jquery.chain.js", "assets/jquery.js", "bin/bowline-gen", "bowline.gemspec", "examples/account.rb", "examples/example.js", "examples/twitter.html", "examples/tweets.rb", "examples/users.rb", "lib/bowline.rb", "lib/bowline/binders.rb", "lib/bowline/binders/collection.rb", "lib/bowline/binders/singleton.rb", "lib/bowline/commands/console.rb", "lib/bowline/commands/generate.rb", "lib/bowline/commands/run.rb", "lib/bowline/ext/array.rb", "lib/bowline/ext/class.rb", "lib/bowline/ext/object.rb", "lib/bowline/ext/string.rb", "lib/bowline/gem_dependency.rb", "lib/bowline/generators.rb", "lib/bowline/generators/application.rb", "lib/bowline/generators/binder.rb", "lib/bowline/generators/migration.rb", "lib/bowline/generators/model.rb", "lib/bowline/initializer.rb", "lib/bowline/jquery.rb", "lib/bowline/observer.rb", "lib/bowline/tasks/app.rake", "lib/bowline/tasks/bowline.rb", "lib/bowline/tasks/database.rake", "lib/bowline/tasks/log.rake", "lib/bowline/tasks/misk.rake", "templates/Rakefile", "templates/binder.rb", "templates/config/application.yml", "templates/config/boot.rb", "templates/config/database.yml", "templates/config/environment.rb", "templates/config/manifest", "templates/config/tiapp.xml", "templates/gitignore", "templates/migration.rb", "templates/model.rb", "templates/public/index.html", "templates/public/javascripts/application.js", "templates/public/stylesheets/application.css", "templates/script/console", "templates/script/init", "templates/script/run"]
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.homepage = %q{http://github.com/maccman/bowline}
|
18
|
+
s.rdoc_options = ["--main", "README.txt"]
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.rubyforge_project = %q{maccman}
|
21
|
+
s.rubygems_version = %q{1.3.2}
|
22
|
+
s.summary = %q{Ruby desktop application framework}
|
23
|
+
|
24
|
+
if s.respond_to? :specification_version then
|
25
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
26
|
+
s.specification_version = 3
|
27
|
+
|
28
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
29
|
+
s.add_runtime_dependency(%q<templater>, [">= 0.3.2"])
|
30
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 2.3.2"])
|
31
|
+
s.add_development_dependency(%q<newgem>, [">= 1.3.0"])
|
32
|
+
s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
|
33
|
+
else
|
34
|
+
s.add_dependency(%q<templater>, [">= 0.3.2"])
|
35
|
+
s.add_dependency(%q<activesupport>, [">= 2.3.2"])
|
36
|
+
s.add_dependency(%q<newgem>, [">= 1.3.0"])
|
37
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
38
|
+
end
|
39
|
+
else
|
40
|
+
s.add_dependency(%q<templater>, [">= 0.3.2"])
|
41
|
+
s.add_dependency(%q<activesupport>, [">= 2.3.2"])
|
42
|
+
s.add_dependency(%q<newgem>, [">= 1.3.0"])
|
43
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
44
|
+
end
|
45
|
+
end
|
data/examples/account.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Binders
|
2
|
+
class Account < Bowline::Binders::Singleton
|
3
|
+
class << self
|
4
|
+
# self.collection is a special method
|
5
|
+
# Basically it'll update users on the client side
|
6
|
+
def index
|
7
|
+
self.item = current_account
|
8
|
+
end
|
9
|
+
|
10
|
+
def destroy
|
11
|
+
current_account.destroy
|
12
|
+
self.item = nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Everything has a js_id which is basically the lowercase classname + _ + self.id
|
17
|
+
def highlight
|
18
|
+
# Calls $(element).highlight()
|
19
|
+
self.element.highlight
|
20
|
+
end
|
21
|
+
|
22
|
+
# Overrides charge on user
|
23
|
+
def charge!
|
24
|
+
# calls charge on model (i.e. do sql commit )
|
25
|
+
self.item.charge!
|
26
|
+
# Now gui stuff
|
27
|
+
flash[:notice] = "Successfully charged"
|
28
|
+
highlight
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/examples/example.js
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$('#users').bowline('users_binder');
|
2
|
+
|
3
|
+
var user = $('#users').items(10);
|
4
|
+
user.update({name: 'Alex'}); // will automatiinvokey
|
5
|
+
user.item().errors //=> []
|
6
|
+
|
7
|
+
// Deletes item from DOM too
|
8
|
+
item.destroy()
|
9
|
+
|
10
|
+
// invoke collection method
|
11
|
+
// This will invoke UserBinder.admins and fill #users with admins
|
12
|
+
$('#users').invoke('admins');
|
13
|
+
|
14
|
+
// invoke singleton method
|
15
|
+
$('#users').items(10).invoke('charge!');
|
16
|
+
|
17
|
+
// invoke charge! on every user
|
18
|
+
$('#users').items().invoke('charge!')
|
19
|
+
|
20
|
+
// // For binding over a http connection - an async invoke
|
21
|
+
// // last argument is a function
|
22
|
+
// $('#users').items(10).invoke('charge!', function(){
|
23
|
+
//
|
24
|
+
// })
|
data/examples/tweets.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Binders
|
2
|
+
class Tweets < Bowline::Binders::Collection
|
3
|
+
class << self
|
4
|
+
def index
|
5
|
+
self.items = timeline
|
6
|
+
end
|
7
|
+
|
8
|
+
def update(status)
|
9
|
+
twitter.update(status)
|
10
|
+
index # update timeline
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
def twitter
|
15
|
+
httpauth = Twitter::HTTPAuth.new('user', 'pass')
|
16
|
+
Twitter::Base.new(httpauth)
|
17
|
+
end
|
18
|
+
|
19
|
+
def timeline
|
20
|
+
twitter.friends_timeline.collect {|t|
|
21
|
+
t.delete('user')
|
22
|
+
t.to_hash
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end # Binders
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
2
|
+
"http://www.w3.org/TR/html4/strict.dtd">
|
3
|
+
|
4
|
+
<html lang="en">
|
5
|
+
<head>
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
7
|
+
<title>Twitter</title>
|
8
|
+
<!--
|
9
|
+
<script src="http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js" type="text/javascript"></script>
|
10
|
+
-->
|
11
|
+
<script src="javascripts/jquery.js" type="text/javascript" charset="utf-8"></script>
|
12
|
+
<script src="javascripts/jquery.chain.js" type="text/javascript" charset="utf-8"></script>
|
13
|
+
<script src="javascripts/jquery.bowline.js" type="text/javascript" charset="utf-8"></script>
|
14
|
+
<script src="../script/init" type="text/ruby" charset="utf-8"></script>
|
15
|
+
<script src="javascripts/application.js" type="text/javascript" charset="utf-8"></script>
|
16
|
+
<link rel="stylesheet" href="stylesheets/application.css" type="text/css" charset="utf-8">
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
jQuery(function($){
|
19
|
+
var tweets = $('#tweets').bowline('tweets');
|
20
|
+
tweets.invoke('index');
|
21
|
+
|
22
|
+
$('#updateSubmit').click(function(){
|
23
|
+
tweets.invoke('update', $('#updateText').val());
|
24
|
+
return false;
|
25
|
+
})
|
26
|
+
});
|
27
|
+
</script>
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div id="tweets">
|
31
|
+
<div class="item">
|
32
|
+
<span class="text"></span>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
|
36
|
+
<input type="text" id="updateText">
|
37
|
+
<input type="submit" value="Update →" id="updateSubmit">
|
38
|
+
</body>
|
39
|
+
</html>
|
data/examples/users.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Binders
|
2
|
+
class Users < Bowline::Binders::Collection
|
3
|
+
class << self
|
4
|
+
# self.items is a special method
|
5
|
+
# Basically it'll update users on the client side
|
6
|
+
def index
|
7
|
+
self.items = User.all
|
8
|
+
end
|
9
|
+
|
10
|
+
def admins
|
11
|
+
self.items = User.admins.all
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def update(attrs)
|
16
|
+
if @item.update_attributes(attrs)
|
17
|
+
flash[:notice] = "Successfully updated"
|
18
|
+
else
|
19
|
+
flash[:notice] = "Errors updating users"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def highlight
|
24
|
+
# Calls $('user_1').highlight()
|
25
|
+
self.element.highlight
|
26
|
+
end
|
27
|
+
|
28
|
+
# Overrides charge on user
|
29
|
+
def charge!
|
30
|
+
# calls charge! on model (i.e. do sql commit )
|
31
|
+
self.item.charge!
|
32
|
+
# Now gui stuff
|
33
|
+
flash[:notice] = "Successfully charged"
|
34
|
+
highlight
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/bowline.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Bowline
|
2
|
+
VERSION = '0.1.6'
|
3
|
+
|
4
|
+
# The raw JavaScript window object
|
5
|
+
def self.js
|
6
|
+
if defined?($app_window)
|
7
|
+
$app_window
|
8
|
+
else
|
9
|
+
Class.new {
|
10
|
+
def self.method_missing(*a)
|
11
|
+
Bowline.logger.info "Sending to Window: #{a.inspect}"
|
12
|
+
self
|
13
|
+
end
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Change which page we're on
|
19
|
+
def self.show_view(name)
|
20
|
+
js.window.location = "app://public/#{name}.html"
|
21
|
+
end
|
22
|
+
|
23
|
+
class Base
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
28
|
+
|
29
|
+
require 'bowline/ext/object'
|
30
|
+
require 'bowline/ext/array'
|
31
|
+
require 'bowline/ext/class'
|
32
|
+
require 'bowline/ext/string'
|
33
|
+
|
34
|
+
require 'bowline/gem_dependency'
|
35
|
+
require 'bowline/initializer'
|
36
|
+
|
37
|
+
require 'bowline/jquery'
|
38
|
+
require 'bowline/observer'
|
39
|
+
|
40
|
+
require 'bowline/binders'
|
41
|
+
require 'bowline/binders/collection'
|
42
|
+
require 'bowline/binders/singleton'
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module Bowline
|
2
|
+
module Binders
|
3
|
+
class Base
|
4
|
+
cattr_accessor :params
|
5
|
+
|
6
|
+
class << self
|
7
|
+
# See Bowline::js
|
8
|
+
def js
|
9
|
+
Bowline::js
|
10
|
+
end
|
11
|
+
|
12
|
+
# Equivalent of the 'jQuery' function
|
13
|
+
def jquery
|
14
|
+
@@jquery ||= JQuery.new
|
15
|
+
end
|
16
|
+
|
17
|
+
# See the Observer class
|
18
|
+
def observer
|
19
|
+
@@observer ||= Observer.new
|
20
|
+
end
|
21
|
+
|
22
|
+
# See Bowline::logger
|
23
|
+
def logger
|
24
|
+
Bowline::logger
|
25
|
+
end
|
26
|
+
|
27
|
+
# See Bowline::show_view
|
28
|
+
def show_view(*args)
|
29
|
+
Bowline::show_view(*args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def params=(p)
|
33
|
+
case p
|
34
|
+
when String
|
35
|
+
# Params comes in a string (since it's a
|
36
|
+
# serialized form) - we need to make it into
|
37
|
+
# a nestled hash.
|
38
|
+
# Stolen from Ramaze
|
39
|
+
m = proc {|_,o,n|o.merge(n,&m)}
|
40
|
+
@@params = params.inject({}) do |hash, (key, value)|
|
41
|
+
parts = key.split(/[\]\[]+/)
|
42
|
+
hash.merge(parts.reverse.inject(value) { |x, i| {i => x} }, &m)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
@@params = p
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def setup(d)
|
50
|
+
@@elements ||= []
|
51
|
+
@@elements << d
|
52
|
+
self.item_sync!
|
53
|
+
end
|
54
|
+
|
55
|
+
def instance(el)
|
56
|
+
self.new(el).method(:send)
|
57
|
+
end
|
58
|
+
|
59
|
+
# todo - flash?
|
60
|
+
|
61
|
+
def inherited(child)
|
62
|
+
return if self == Bowline::Binders::Base
|
63
|
+
return if child == Bowline::Binders::Singleton
|
64
|
+
return if child == Bowline::Binders::Collection
|
65
|
+
name = child.name.underscore
|
66
|
+
name = name.split('/').last
|
67
|
+
js.send("bowline_#{name}_setup=", child.method(:setup))
|
68
|
+
js.send("bowline_#{name}_instance=", child.method(:instance))
|
69
|
+
js.send("bowline_#{name}=", child.method(:send))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_reader :element
|
74
|
+
attr_reader :item
|
75
|
+
|
76
|
+
# Todo
|
77
|
+
# We want initialize method to take
|
78
|
+
# no argument, and for every item in items
|
79
|
+
# to have initialize called on startup,
|
80
|
+
# so they can set up event handlers etc
|
81
|
+
def self.new(element, *args) #:nodoc:
|
82
|
+
allocate.instance_eval do
|
83
|
+
# jQuery element
|
84
|
+
@element = element
|
85
|
+
# Calling chain.js 'item' function
|
86
|
+
@item = element.item()
|
87
|
+
if @item
|
88
|
+
@item.with_indifferent_access
|
89
|
+
# If possible, find Ruby object
|
90
|
+
if @item[:id] && respond_to?(:find)
|
91
|
+
@item = find(@item[:id])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
initialize(*args)
|
96
|
+
self
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Trigger jQuery events on this element
|
101
|
+
def trigger(event, data = nil)
|
102
|
+
self.element.trigger(event, data)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Bind event to element:
|
106
|
+
# bind(:click) { puts "element clicked" }
|
107
|
+
# todo - two events with the same item/event overwrite each other
|
108
|
+
# todo - need initalize method on class - so we can set events there
|
109
|
+
def bind(event, method_name, &block)
|
110
|
+
event_name = [event, item_id].join(":")
|
111
|
+
callback = block
|
112
|
+
callback ||= begin
|
113
|
+
method_name.is_a?(Method) ?
|
114
|
+
method_name : method(method_name)
|
115
|
+
end
|
116
|
+
self.observer.append(event_name, callback)
|
117
|
+
self.element.bind(
|
118
|
+
event.to_s,
|
119
|
+
event_name,
|
120
|
+
self.observer.method(:call)
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
def click(method_name = nil, &block)
|
125
|
+
bind(:click, method, &block)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Raw DOM element
|
129
|
+
def dom
|
130
|
+
self.element[0]
|
131
|
+
end
|
132
|
+
|
133
|
+
# Shortcut methods
|
134
|
+
|
135
|
+
# See self.class.show_view
|
136
|
+
def show_view(*args)
|
137
|
+
self.class.show_view(*args)
|
138
|
+
end
|
139
|
+
|
140
|
+
# See self.class.js
|
141
|
+
def js
|
142
|
+
self.class.js
|
143
|
+
end
|
144
|
+
alias :page :js
|
145
|
+
|
146
|
+
# See self.class.jquery
|
147
|
+
def jquery
|
148
|
+
self.class.jquery
|
149
|
+
end
|
150
|
+
|
151
|
+
# See self.class.observer
|
152
|
+
def observer
|
153
|
+
self.class.observer
|
154
|
+
end
|
155
|
+
|
156
|
+
# See self.class.logger
|
157
|
+
def logger
|
158
|
+
self.class.logger
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
# This is just a unique identifier
|
163
|
+
# for the item - and isn't
|
164
|
+
# used in the dom
|
165
|
+
def item_id
|
166
|
+
if item.respond_to?(:dom_id)
|
167
|
+
item.dom_id
|
168
|
+
else
|
169
|
+
[
|
170
|
+
item.id,
|
171
|
+
self.class.name.underscore
|
172
|
+
].join("_")
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Bowline
|
2
|
+
module Binders
|
3
|
+
class Collection < Base
|
4
|
+
cattr_accessor :items
|
5
|
+
class << self
|
6
|
+
def items=(args)
|
7
|
+
@@items = args
|
8
|
+
self.item_sync!
|
9
|
+
@@items
|
10
|
+
end
|
11
|
+
|
12
|
+
def item_sync!
|
13
|
+
return unless @@items && @@elements
|
14
|
+
@@elements.each {|i|
|
15
|
+
i.updateCollection(@@items.to_js)
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def find(id)
|
20
|
+
@@items.find {|item|
|
21
|
+
item.id == id if item.respond_to?(:id)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|