bowline 0.5.3 → 0.5.4

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 (47) hide show
  1. data/.gitignore +1 -0
  2. data/README.txt +62 -62
  3. data/Rakefile +10 -0
  4. data/TODO +3 -1
  5. data/VERSION +1 -1
  6. data/assets/bowline.js +118 -3
  7. data/bowline.gemspec +6 -6
  8. data/examples/example.js +2 -15
  9. data/examples/tweet.rb +35 -0
  10. data/examples/tweets_binder.rb +6 -0
  11. data/examples/twitter.html +6 -8
  12. data/examples/users.rb +8 -14
  13. data/lib/bowline/binders.rb +130 -42
  14. data/lib/bowline/dependencies/lib/dependencies.rb +2 -1
  15. data/lib/bowline/dependencies/lib/ext/rubygems.rb +4 -4
  16. data/lib/bowline/desktop.rb +11 -2
  17. data/lib/bowline/desktop/app.rb +7 -3
  18. data/lib/bowline/desktop/bridge.rb +8 -9
  19. data/lib/bowline/desktop/clipboard.rb +11 -2
  20. data/lib/bowline/desktop/dialog.rb +19 -0
  21. data/lib/bowline/desktop/dock.rb +14 -3
  22. data/lib/bowline/desktop/host.rb +13 -4
  23. data/lib/bowline/desktop/js.rb +2 -2
  24. data/lib/bowline/desktop/misc.rb +7 -3
  25. data/lib/bowline/desktop/network.rb +1 -1
  26. data/lib/bowline/desktop/proxy.rb +28 -30
  27. data/lib/bowline/desktop/sound.rb +3 -2
  28. data/lib/bowline/desktop/window.rb +147 -21
  29. data/lib/bowline/desktop/window_manager.rb +53 -5
  30. data/lib/bowline/desktop/window_methods.rb +2 -2
  31. data/lib/bowline/ext/object.rb +1 -1
  32. data/lib/bowline/generators.rb +1 -1
  33. data/lib/bowline/generators/binder.rb +1 -1
  34. data/lib/bowline/helpers.rb +1 -1
  35. data/lib/bowline/initializer.rb +37 -4
  36. data/lib/bowline/library.rb +11 -0
  37. data/lib/bowline/local_model.rb +45 -19
  38. data/lib/bowline/logging.rb +1 -1
  39. data/lib/bowline/platform.rb +8 -6
  40. data/lib/bowline/tasks/app.rake +4 -3
  41. data/lib/bowline/version.rb +1 -1
  42. data/lib/bowline/watcher.rb +18 -8
  43. data/templates/binder.rb +1 -1
  44. data/vendor/pathname.rb +0 -4
  45. metadata +6 -6
  46. data/examples/account.rb +0 -31
  47. data/examples/tweets.rb +0 -28
data/examples/tweet.rb ADDED
@@ -0,0 +1,35 @@
1
+ class Tweet < Bowline::LocalModel
2
+ class << self
3
+ def poll
4
+ destroy_all
5
+ populate(timeline)
6
+ end
7
+
8
+ def timeline
9
+ twitter.friends_timeline.collect {|t|
10
+ t.delete('user')
11
+ t.to_hash
12
+ }
13
+ end
14
+
15
+ def update(status)
16
+ twitter.update(status)
17
+ end
18
+
19
+ private
20
+ def twitter
21
+ httpauth = Twitter::HTTPAuth.new(
22
+ AppConfig.username,
23
+ AppConfig.password
24
+ )
25
+ Twitter::Base.new(httpauth)
26
+ end
27
+ end
28
+ end
29
+
30
+ Thread.new do
31
+ loop do
32
+ Tweet.poll
33
+ sleep 60
34
+ end
35
+ end
@@ -0,0 +1,6 @@
1
+ class TweetsBinder < Bowline::Binders::Base
2
+ bind Tweet
3
+ def self.update(status)
4
+ klass.update(status)
5
+ end
6
+ end
@@ -6,18 +6,16 @@
6
6
  <link rel="stylesheet" href="stylesheets/application.css" type="text/css" charset="utf-8">
7
7
  <script src="javascripts/jquery.js" type="text/javascript" charset="utf-8"></script>
8
8
  <script src="javascripts/jquery.chain.js" type="text/javascript" charset="utf-8"></script>
9
- <script src="javascripts/jquery.bowline.js" type="text/javascript" charset="utf-8"></script>
9
+ <script src="javascripts/json2.js" type="text/javascript" charset="utf-8"></script>
10
+ <script src="javascripts/bowline.js" type="text/javascript" charset="utf-8"></script>
10
11
  <script src="javascripts/application.js" type="text/javascript" charset="utf-8"></script>
11
12
  <script type="text/javascript" charset="utf-8">
12
13
  jQuery(function($){
13
- $.bowline.ready(function(){
14
- var tweets = $('#tweets').bowline('tweets');
15
- tweets.invoke('index');
14
+ var tweets = $('#tweets').bindto('tweets');
16
15
 
17
- $('#updateSubmit').click(function(){
18
- tweets.invoke('update', $('#updateText').val());
19
- return false;
20
- });
16
+ $('#updateSubmit').click(function(){
17
+ tweets.invoke('update', $('#updateText').val());
18
+ return false;
21
19
  });
22
20
  });
23
21
  </script>
data/examples/users.rb CHANGED
@@ -1,12 +1,7 @@
1
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
-
2
+ class Users < Bowline::Binders::Base
3
+ bind User
4
+ class << self
10
5
  def admins
11
6
  self.items = User.admins.all
12
7
  end
@@ -14,23 +9,22 @@ module Binders
14
9
 
15
10
  def update(attrs)
16
11
  if @item.update_attributes(attrs)
17
- flash[:notice] = "Successfully updated"
12
+ page.flash("Successfully updated").call
18
13
  else
19
- flash[:notice] = "Errors updating users"
14
+ page.flash_error("Errors updating users").call
20
15
  end
21
16
  end
22
17
 
23
18
  def highlight
24
19
  # Calls $('user_1').highlight()
25
- self.element.highlight
20
+ self.element.highlight.call
26
21
  end
27
22
 
28
- # Overrides charge on user
29
23
  def charge!
30
- # calls charge! on model (i.e. do sql commit )
24
+ # calls charge! on model (i.e. do SQL commit )
31
25
  self.item.charge!
32
26
  # Now gui stuff
33
- flash[:notice] = "Successfully charged"
27
+ page.flash("Charged!")
34
28
  highlight
35
29
  end
36
30
  end
@@ -1,23 +1,87 @@
1
1
  module Bowline
2
2
  module Binders
3
+ # Binders are a central part of Bowline. They perform two main functions:
4
+ # 1) Bind a model to the view, so any changes to the model get automatically
5
+ # reflected in the view.
6
+ # 2) View abstraction of the model. You can define view specific class & instance
7
+ # methods, and easily call them from bound JavaScript objects.
8
+ #
9
+ # To use a binder, you first need to bind it to a model using the bind method.
10
+ # Example:
11
+ # class UsersBinder < Bowline::Binders::Base
12
+ # bind User
13
+ # end
14
+ #
15
+ # Once a class is bound, any updates to the model automatically update any bound HTML.
16
+ # The class names in the HTML are tied to the model's attribute names.
17
+ # You can bind HTML using the bowline.js bindup function.
18
+ # Example:
19
+ # <div id="users">
20
+ # <div class="item">
21
+ # <span class="name"></span>
22
+ # </div>
23
+ # </div>
24
+ # <script>
25
+ # $("#users").bindup('UsersBinder');
26
+ # </script>
27
+ #
28
+ # =Class methods
29
+ #
30
+ # You can define class methods on your binder, and call them using JavaScript
31
+ # using the invoke function on the bound HTML element.
32
+ # Example:
33
+ # <script>
34
+ # var users = $("#users").bindup('UsersBinder');
35
+ # users.invoke("method_name", "arg1", "arg2")
36
+ # </script>
37
+ #
38
+ # =Instance methods
39
+ #
40
+ # You can call your binders instance method from JavaScript by calling the invoke
41
+ # function on the generated HTML elements. Your binder's instance methods have access
42
+ # to an 'element' variable, which is the jQuery element, and a 'item' variable, which
43
+ # is the bound model's instance record.
44
+ #
45
+ # Example:
46
+ # class UsersBinder < Bowline::Binders::Base
47
+ # bind User
48
+ # def charge!
49
+ # #...
50
+ # end
51
+ # end
52
+ #
53
+ # <script>
54
+ # $('#users').items(10).invoke('charge!');
55
+ # </script>
56
+ #
57
+ # For more documentation on Bowline's JavaScript API, see bowline.js
3
58
  class Base
4
59
  extend Bowline::Watcher::Base
5
60
  extend Bowline::Desktop::Bridge::ClassMethods
6
61
  js_expose
7
62
 
8
63
  class << self
64
+ # An array of window currently bound.
9
65
  def windows
10
66
  @windows ||= []
11
67
  end
12
68
 
13
- # Called by JS when first bound
14
- def setup(window)
69
+ # Called by a window's JavaScript whenever that window is bound to this Binder.
70
+ # This method populates the window's HTML with all bound class' records.
71
+ # Override this if you don't want to send all the class' records to the window.
72
+ # Example:
73
+ # def setup(window)
74
+ # super(window, last_10_tweets)
75
+ # end
76
+ def setup(window, items = all)
15
77
  self.windows << window
16
- self.items = all
78
+ window.bowline.populate(
79
+ name, items.to_js
80
+ ).call
17
81
  true
18
82
  end
19
83
 
20
- def js_invoke(window, method, *args)
84
+ def js_invoke(window, method, *args) #:nodoc:
21
85
  if method == :setup
22
86
  setup(window)
23
87
  else
@@ -29,19 +93,28 @@ module Bowline
29
93
  self.new(id).send(meth, *args)
30
94
  end
31
95
 
96
+ # Calls .find on the klass sent to the bind method.
97
+ # This is used internally, to find records when the page
98
+ # invoke instance methods.
32
99
  def find(id)
33
100
  klass.find(id)
34
101
  end
35
-
102
+
103
+ # Calls .all on the klass sent to the bind method.
104
+ # This method is called internally by the setup method.
36
105
  def all
37
106
  klass.all
38
107
  end
39
108
 
40
- def items=(items) #:nodoc:
109
+ # Set the binder's items. This will replace all items, and update the HTML.
110
+ def items=(items)
41
111
  bowline.populate(name, items.to_js).call
42
112
  end
43
113
 
44
- def created(item) #:nodoc:
114
+ # Add a new item to the binder, updating the HTML.
115
+ # This method is normally only called internally by
116
+ # the bound class's after_create callback.
117
+ def created(item)
45
118
  bowline.created(
46
119
  name,
47
120
  item.id,
@@ -49,7 +122,10 @@ module Bowline
49
122
  ).call
50
123
  end
51
124
 
52
- def updated(item) #:nodoc:
125
+ # Update an item on the binder, updating the HTML.
126
+ # This method is normally only called internally by
127
+ # the bound class's after_update callback.
128
+ def updated(item)
53
129
  bowline.updated(
54
130
  name,
55
131
  item.id,
@@ -57,7 +133,10 @@ module Bowline
57
133
  ).call
58
134
  end
59
135
 
60
- def removed(item) #:nodoc:
136
+ # Remove an item from the binder, updating the HTML.
137
+ # This method is normally only called internally by
138
+ # the bound class's after_destroy callback.
139
+ def removed(item)
61
140
  bowline.removed(
62
141
  name,
63
142
  item.id
@@ -65,41 +144,45 @@ module Bowline
65
144
  end
66
145
 
67
146
  protected
68
- # Associate the binder with a model
69
- # to setup callbacks so changes to the
70
- # model are automatically reflected in
71
- # the view. Usage:
72
- # expose Post
147
+ # Associate the binder with a model to setup callbacks so
148
+ # changes to the model are automatically reflected in the view.
149
+ # Example:
150
+ # bind Post
73
151
  #
74
- # When the exposed class is created/updated/deleted
152
+ # When the bound class is created/updated/deleted
75
153
  # the binder's callbacks are executed and the view
76
154
  # updated accordingly.
77
- #
78
- # klass needs to respond to:
79
- # * all
80
- # * find(id)
81
- # * after_create(method)
82
- # * after_update(method)
83
- # * after_destroy(method)
155
+ #
156
+ # Classes inheriting fromActiveRecord and Bowline::LocalModel are
157
+ # automatically compatable, but if you're using your own custom model
158
+ # you need to make sure it responds to the following methods:
159
+ # * all - return all records
160
+ # * find(id) - find record by id
161
+ # * after_create(method) - after_create callback
162
+ # * after_update(method) - after_update callback
163
+ # * after_destroy(method) - after_destroy callback
84
164
  #
85
- # klass instance needs to respond to:
86
- # * id
165
+ # The klass' instance needs to respond to:
166
+ # * id - returns record id
167
+ # * to_js - return record's attribute hash
87
168
  #
88
- # You can override .to_js on the model instance
89
- # in order to return specific attributes for the view
90
- def expose(klass)
169
+ # You can override the to_js method on the model instance
170
+ # in order to return specific attributes for the view.
171
+ def bind(klass)
91
172
  @klass = klass
92
173
  @klass.after_create(method(:created))
93
174
  @klass.after_update(method(:updated))
94
175
  @klass.after_destroy(method(:removed))
95
176
  end
96
177
 
97
- # Returns class set by the 'expose' method
178
+ # Returns class set by the 'bind' method
98
179
  def klass
99
- @klass || raise("klass not set - see expose method")
180
+ @klass || raise("klass not set - see bind method")
100
181
  end
101
182
 
102
- # JavaScript proxy to the page:
183
+ # JavaScript proxy to the page.
184
+ # See Bowline::Desktop::Proxy for more information.
185
+ # Example:
103
186
  # page.myFunc(1,2,3).call
104
187
  def page
105
188
  Bowline::Desktop::Proxy.new(
@@ -107,14 +190,18 @@ module Bowline
107
190
  )
108
191
  end
109
192
 
110
- # JavaScript proxy to the Bowline object:
193
+ # JavaScript proxy to the Bowline object.
194
+ # See Bowline::Desktop::Proxy for more information.
195
+ # Example:
111
196
  # bowline.log("msg").call
112
197
  def bowline
113
198
  page.Bowline
114
199
  end
115
200
 
116
- # Javascript proxy to jQuery:
117
- # jquery.getJSON("http://example.com")
201
+ # Javascript proxy to jQuery.
202
+ # See Bowline::Desktop::Proxy for more information.
203
+ # Example:
204
+ # jquery.getJSON("http://example.com").call
118
205
  def jquery
119
206
  page.jQuery
120
207
  end
@@ -125,7 +212,8 @@ module Bowline
125
212
  end
126
213
 
127
214
  # Trigger events on all elements
128
- # bound to this binder:
215
+ # bound to this binder.
216
+ # Example:
129
217
  # trigger(:reload, {:key => :value})
130
218
  def trigger(event, data = nil)
131
219
  bowline.trigger(
@@ -152,14 +240,13 @@ module Bowline
152
240
  name.to_s
153
241
  end
154
242
  end
155
-
243
+
244
+ # jQuery element object
156
245
  attr_reader :element
157
- attr_reader :item
158
246
 
159
- # Instance of an element on the view.
160
- #
161
- # item.destroy
162
- # element.highlight.call
247
+ # Instance of the bound class' record
248
+ attr_reader :item
249
+
163
250
  def initialize(id, *args) #:nodoc:
164
251
  @element = self.class.bowline.element(
165
252
  self.class.name, id
@@ -168,7 +255,8 @@ module Bowline
168
255
  end
169
256
 
170
257
  protected
171
- # Trigger jQuery events on this element:
258
+ # Trigger jQuery events on this element.
259
+ # Example:
172
260
  # trigger(:highlight)
173
261
  def trigger(event, data = nil)
174
262
  element.trigger(
@@ -184,7 +272,7 @@ module Bowline
184
272
 
185
273
  # Shortcut methods
186
274
 
187
- # See self.class.js
275
+ # See self.class.page
188
276
  def page
189
277
  self.class.page
190
278
  end
@@ -1,4 +1,5 @@
1
- module Dependencies; end
1
+ module Dependencies #:nodoc: all
2
+ end
2
3
 
3
4
  Dir[File.join(File.dirname(__FILE__), 'dependencies', '*.rb')].each do |file|
4
5
  require file
@@ -22,7 +22,7 @@ Gem.pre_install_hooks.push(proc do |installer|
22
22
  end
23
23
  end)
24
24
 
25
- class ::Gem::Uninstaller
25
+ class ::Gem::Uninstaller #:nodoc:
26
26
  def self._with_silent_ui
27
27
 
28
28
  ui = Gem::DefaultUserInteraction.ui
@@ -64,7 +64,7 @@ Gem.post_install_hooks.push(proc do |installer|
64
64
  )
65
65
  end)
66
66
 
67
- class ::Gem::DependencyInstaller
67
+ class ::Gem::DependencyInstaller #:nodoc:
68
68
  alias old_fg find_gems_with_sources
69
69
 
70
70
  def find_gems_with_sources(dep)
@@ -78,7 +78,7 @@ class ::Gem::DependencyInstaller
78
78
  end
79
79
  end
80
80
 
81
- class ::Gem::SpecFetcher
81
+ class ::Gem::SpecFetcher #:nodoc:
82
82
  alias old_fetch fetch
83
83
  def fetch(*args) # in rubygems 1.3.2 fetch takes 4 parameters
84
84
  dependency, all, matching_platform, prerelease = *args
@@ -102,7 +102,7 @@ class ::Gem::SpecFetcher
102
102
  end
103
103
  end
104
104
 
105
- class ::Gem::Specification
105
+ class ::Gem::Specification #:nodoc:
106
106
  def recursive_dependencies(from, index = Gem.source_index)
107
107
  specs = self.runtime_dependencies.map do |dep|
108
108
  spec = index.search(dep).last
@@ -4,19 +4,28 @@ module Bowline
4
4
  extend Bowline::Watcher::Base
5
5
  watch :on_tick, :on_idle
6
6
 
7
+ ##
8
+ # :singleton-method: on_tick(method = nil, &block)
9
+ # A Watcher event method that gets called every few microseconds,
10
+ # inside the application's main thread.
11
+ # Example:
12
+ # on_tick { puts "App tick" }
13
+
14
+ # Return true if we're currently
15
+ # being executed by bowline-desktop.
7
16
  def enabled?
8
17
  $0 == "bowline"
9
18
  end
10
19
  module_function :enabled?
11
20
 
12
- def idle
21
+ def idle #:nodoc:
13
22
  watcher.call(:on_idle)
14
23
  rescue => e
15
24
  log_error e
16
25
  end
17
26
  module_function :idle
18
27
 
19
- def tick
28
+ def tick #:nodoc:
20
29
  watcher.call(:on_tick)
21
30
  rescue => e
22
31
  log_error e