maccman-bowline 0.1.1

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.
Files changed (59) hide show
  1. data/History.txt +4 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Manifest.txt +58 -0
  4. data/README.txt +113 -0
  5. data/Rakefile +24 -0
  6. data/assets/jquery.bowline.js +96 -0
  7. data/assets/jquery.chain.js +2348 -0
  8. data/assets/jquery.js +3549 -0
  9. data/bin/bowline-gen +6 -0
  10. data/bowline.gemspec +42 -0
  11. data/examples/account_binder.rb +29 -0
  12. data/examples/example.js +24 -0
  13. data/examples/twitter.html +43 -0
  14. data/examples/twitter_binder.rb +40 -0
  15. data/examples/twitter_login.html +29 -0
  16. data/examples/users_binder.rb +39 -0
  17. data/lib/bowline.rb +42 -0
  18. data/lib/bowline/binders.rb +177 -0
  19. data/lib/bowline/binders/collection.rb +27 -0
  20. data/lib/bowline/binders/singleton.rb +25 -0
  21. data/lib/bowline/commands/console.rb +27 -0
  22. data/lib/bowline/commands/generate.rb +1 -0
  23. data/lib/bowline/commands/run.rb +13 -0
  24. data/lib/bowline/ext/array.rb +5 -0
  25. data/lib/bowline/ext/class.rb +51 -0
  26. data/lib/bowline/ext/object.rb +12 -0
  27. data/lib/bowline/ext/string.rb +9 -0
  28. data/lib/bowline/gem_dependency.rb +42 -0
  29. data/lib/bowline/generators.rb +59 -0
  30. data/lib/bowline/generators/application.rb +49 -0
  31. data/lib/bowline/generators/binder.rb +25 -0
  32. data/lib/bowline/generators/migration.rb +51 -0
  33. data/lib/bowline/generators/model.rb +20 -0
  34. data/lib/bowline/initializer.rb +596 -0
  35. data/lib/bowline/jquery.rb +31 -0
  36. data/lib/bowline/observer.rb +43 -0
  37. data/lib/bowline/tasks/app.rake +70 -0
  38. data/lib/bowline/tasks/bowline.rb +8 -0
  39. data/lib/bowline/tasks/database.rake +167 -0
  40. data/lib/bowline/tasks/log.rake +9 -0
  41. data/lib/bowline/tasks/misk.rake +3 -0
  42. data/templates/Rakefile +7 -0
  43. data/templates/binder.rb +9 -0
  44. data/templates/config/application.yml +1 -0
  45. data/templates/config/boot.rb +21 -0
  46. data/templates/config/database.yml +4 -0
  47. data/templates/config/environment.rb +12 -0
  48. data/templates/config/manifest +18 -0
  49. data/templates/config/tiapp.xml +24 -0
  50. data/templates/gitignore +15 -0
  51. data/templates/migration.rb +7 -0
  52. data/templates/model.rb +4 -0
  53. data/templates/public/index.html.erb +23 -0
  54. data/templates/public/javascripts/application.js +0 -0
  55. data/templates/public/stylesheets/application.css +0 -0
  56. data/templates/script/console +3 -0
  57. data/templates/script/init +11 -0
  58. data/templates/script/run +3 -0
  59. metadata +143 -0
data/bin/bowline-gen ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), *%w[.. lib bowline])
4
+ require 'bowline/generators'
5
+
6
+ Bowline::Generators.run_cli(Dir.pwd, 'bowline', Bowline::VERSION, ARGV)
data/bowline.gemspec ADDED
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{bowline}
5
+ s.version = "0.1.1"
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-23}
10
+ s.default_executable = %q{bowline-gen}
11
+ s.description = %q{My take on Ruby desktop GUIs}
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 = ["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_binder.rb", "examples/example.js", "examples/twitter.html", "examples/twitter_binder.rb", "examples/twitter_login.html", "examples/users_binder.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.erb", "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{My take on Ruby desktop GUIs}
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_development_dependency(%q<newgem>, [">= 1.3.0"])
31
+ s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
32
+ else
33
+ s.add_dependency(%q<templater>, [">= 0.3.2"])
34
+ s.add_dependency(%q<newgem>, [">= 1.3.0"])
35
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
36
+ end
37
+ else
38
+ s.add_dependency(%q<templater>, [">= 0.3.2"])
39
+ s.add_dependency(%q<newgem>, [">= 1.3.0"])
40
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
41
+ end
42
+ end
@@ -0,0 +1,29 @@
1
+ class AccountBinder < Bowline::Singleton
2
+ class << self
3
+ # self.collection is a special method
4
+ # Basically it'll update users on the client side
5
+ def index
6
+ self.item = current_account
7
+ end
8
+
9
+ def destroy
10
+ current_account.destroy
11
+ self.item = nil
12
+ end
13
+ end
14
+
15
+ # Everything has a js_id which is basically the lowercase classname + _ + self.id
16
+ def highlight
17
+ # Calls $(element).highlight()
18
+ self.element.highlight
19
+ end
20
+
21
+ # Overrides charge on user
22
+ def charge!
23
+ # calls charge on model (i.e. do sql commit )
24
+ self.item.charge!
25
+ # Now gui stuff
26
+ flash[:notice] = "Successfully charged"
27
+ highlight
28
+ end
29
+ end
@@ -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
+ // })
@@ -0,0 +1,43 @@
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
+ <meta name="generator" content="TextMate http://macromates.com/">
9
+ <meta name="author" content="Alex MacCaw">
10
+ <!-- Date: 2009-01-10 -->
11
+ <script src="jquery.js" type="text/javascript" charset="utf-8"></script>
12
+ <script src="chain.js" type="text/javascript" charset="utf-8"></script>
13
+ <script src="bowline.js" type="text/javascript" charset="utf-8"></script>
14
+ <script type="text/javascript" charset="utf-8">
15
+ jQuery(function($){
16
+ var tweets = $('#tweets').bowline.init('twitter_binder');
17
+
18
+ // Update status
19
+ var update = function(){
20
+ tweets.invoke('update', $('#update').val());
21
+ }
22
+
23
+ // Add event handlers
24
+ $('#updateForm').submit(update);
25
+
26
+ tweets.invoke('index');
27
+ });
28
+ </script>
29
+ </head>
30
+ <body>
31
+ <div id="tweets">
32
+ <div class="item">
33
+ <img class="profile_image_url" />
34
+ <span class="text">Loading...</span>
35
+ </div>
36
+ </div>
37
+
38
+ <form action="updateForm" method="get" accept-charset="utf-8">
39
+ <input type="text" name="update" id="update">
40
+ <input type="submit" value="Update &rarr;">
41
+ </form>
42
+ </body>
43
+ </html>
@@ -0,0 +1,40 @@
1
+ class TwitterBinder < Bowline::Collection
2
+ class << self
3
+ # What about filters - should they be implemented?
4
+ cattr_accessor :user, :pass
5
+
6
+ def index
7
+ self.items = twit.timeline(:user)
8
+ end
9
+
10
+ def update(text)
11
+ twit.update(text)
12
+ index # update timeline
13
+ end
14
+
15
+ def login
16
+ self.user, self.pass = params[:user], params[:pass]
17
+ if logged_in?
18
+ show_view :twitter
19
+ index
20
+ else
21
+ js.alert('Credentials invalid')
22
+ end
23
+ end
24
+
25
+ def logged_in?
26
+ return false unless self.user && self.pass
27
+ begin
28
+ twit.timeline && true
29
+ rescue Twitter::CantConnect
30
+ false
31
+ end
32
+ end
33
+
34
+ protected
35
+
36
+ def twit
37
+ Twitter::Base.new(self.user, self.pass)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,29 @@
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_login</title>
8
+ <meta name="generator" content="TextMate http://macromates.com/">
9
+ <meta name="author" content="Alex MacCaw">
10
+ <!-- Date: 2009-01-10 -->
11
+ <script src="jquery.js" type="text/javascript" charset="utf-8"></script>
12
+ <script src="chain.js" type="text/javascript" charset="utf-8"></script>
13
+ <script src="bowline.js" type="text/javascript" charset="utf-8"></script>
14
+ </head>
15
+ <body>
16
+ <script type="text/javascript" charset="utf-8">
17
+ jQuery(function($){
18
+ $.setupForms();
19
+ });
20
+ </script>
21
+
22
+ <form action="twitter_binder.login" method="get">
23
+ <input type="text" name="user" id="user">
24
+ <input type="password" name="pass" id="pass">
25
+
26
+ <p><input type="submit" value="Login &rarr;"></p>
27
+ </form>
28
+ </body>
29
+ </html>
@@ -0,0 +1,39 @@
1
+ class UsersBinder < Bowline::Collection
2
+ class << self
3
+ # self.items is a special method
4
+ # Basically it'll update users on the client side
5
+ def index
6
+ self.items = User.all
7
+ end
8
+
9
+ # def index(offset)
10
+ # self.items = User.all(:conditions => ['id > ?', offset])
11
+ # end
12
+
13
+ def admins
14
+ self.items = User.admins.all
15
+ end
16
+ end
17
+
18
+ def update(attrs)
19
+ if @item.update_attributes(attrs)
20
+ flash[:notice] = "Successfully updated"
21
+ else
22
+ flash[:notice] = "Errors updating users"
23
+ end
24
+ end
25
+
26
+ def highlight
27
+ # Calls $('user_1').highlight()
28
+ self.element.highlight
29
+ end
30
+
31
+ # Overrides charge on user
32
+ def charge!
33
+ # calls charge! on model (i.e. do sql commit )
34
+ self.item.charge!
35
+ # Now gui stuff
36
+ flash[:notice] = "Successfully charged"
37
+ highlight
38
+ end
39
+ end
data/lib/bowline.rb ADDED
@@ -0,0 +1,42 @@
1
+ module Bowline
2
+ VERSION = '0.1.1'
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