bowline 0.4.6 → 0.5.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.
Files changed (63) hide show
  1. data/Rakefile +1 -0
  2. data/TODO +11 -0
  3. data/VERSION +1 -1
  4. data/assets/bowline.js +194 -0
  5. data/assets/json2.js +479 -0
  6. data/assets/osx/Info.plist.erb +45 -0
  7. data/assets/osx/bowline.png +0 -0
  8. data/assets/osx/makeicns +0 -0
  9. data/bowline.gemspec +47 -11
  10. data/lib/bowline.rb +35 -15
  11. data/lib/bowline/binders.rb +168 -131
  12. data/lib/bowline/commands/build.rb +3 -0
  13. data/lib/bowline/commands/generate.rb +3 -1
  14. data/lib/bowline/commands/run.rb +7 -4
  15. data/lib/bowline/desktop.rb +26 -0
  16. data/lib/bowline/desktop/app.rb +9 -0
  17. data/lib/bowline/desktop/bridge.rb +97 -0
  18. data/lib/bowline/desktop/clipboard.rb +9 -0
  19. data/lib/bowline/desktop/dialog.rb +28 -0
  20. data/lib/bowline/desktop/dock.rb +9 -0
  21. data/lib/bowline/desktop/host.rb +10 -0
  22. data/lib/bowline/desktop/js.rb +92 -0
  23. data/lib/bowline/desktop/misc.rb +9 -0
  24. data/lib/bowline/desktop/network.rb +7 -0
  25. data/lib/bowline/desktop/proxy.rb +94 -0
  26. data/lib/bowline/desktop/sound.rb +8 -0
  27. data/lib/bowline/desktop/window.rb +31 -0
  28. data/lib/bowline/desktop/window_manager.rb +72 -0
  29. data/lib/bowline/desktop/window_methods.rb +70 -0
  30. data/lib/bowline/generators.rb +3 -2
  31. data/lib/bowline/generators/application.rb +8 -5
  32. data/lib/bowline/generators/binder.rb +10 -6
  33. data/lib/bowline/generators/model.rb +9 -0
  34. data/lib/bowline/generators/window.rb +28 -0
  35. data/lib/bowline/helpers.rb +0 -3
  36. data/lib/bowline/initializer.rb +65 -11
  37. data/lib/bowline/library.rb +31 -0
  38. data/lib/bowline/local_model.rb +116 -0
  39. data/lib/bowline/logging.rb +23 -0
  40. data/lib/bowline/platform.rb +73 -0
  41. data/lib/bowline/tasks/app.rake +80 -148
  42. data/lib/bowline/tasks/libs.rake +59 -0
  43. data/lib/bowline/version.rb +2 -2
  44. data/lib/bowline/watcher.rb +91 -0
  45. data/templates/binder.rb +2 -8
  46. data/templates/config/environment.rb +3 -2
  47. data/templates/main_window.rb +7 -0
  48. data/templates/model.rb +1 -1
  49. data/templates/public/index.html +2 -1
  50. data/templates/script/build +3 -0
  51. data/templates/script/generate +3 -0
  52. data/templates/script/init +0 -16
  53. data/templates/window.rb +3 -0
  54. data/vendor/pathname.rb +1099 -0
  55. data/vendor/progressbar.rb +236 -0
  56. metadata +48 -9
  57. data/assets/jquery.bowline.js +0 -156
  58. data/lib/bowline/async.rb +0 -29
  59. data/lib/bowline/binders/collection.rb +0 -59
  60. data/lib/bowline/binders/singleton.rb +0 -31
  61. data/lib/bowline/jquery.rb +0 -31
  62. data/lib/bowline/observer.rb +0 -66
  63. data/lib/bowline/window.rb +0 -19
@@ -0,0 +1,3 @@
1
+ require 'rake'
2
+ require 'bowline/tasks/bowline'
3
+ Rake::Task['app:build'].invoke
@@ -1 +1,3 @@
1
- # todo
1
+ require 'bowline/generators'
2
+
3
+ Bowline::Generators.run_cli(APP_ROOT, 'bowline', Bowline::Version::STRING, ARGV)
@@ -1,4 +1,7 @@
1
- require 'rake'
2
- require 'bowline/tasks/bowline'
3
- ENV['TIRUN'] = 'true'
4
- Rake::Task['app'].invoke
1
+ unless Bowline::Library.downloaded?
2
+ require 'rake'
3
+ require 'bowline/tasks/bowline'
4
+ Rake::Task['libs:download'].invoke
5
+ end
6
+
7
+ exec("#{Bowline::Library.desktop_path} #{APP_ROOT}")
@@ -0,0 +1,26 @@
1
+ module Bowline
2
+ module Desktop
3
+ include Bowline::Logging
4
+ extend Bowline::Watcher::Base
5
+ watch :on_tick, :on_idle
6
+
7
+ def enabled?
8
+ $0 == "bowline"
9
+ end
10
+ module_function :enabled?
11
+
12
+ def idle
13
+ watcher.call(:on_idle)
14
+ rescue => e
15
+ log_error e
16
+ end
17
+ module_function :idle
18
+
19
+ def tick
20
+ watcher.call(:on_tick)
21
+ rescue => e
22
+ log_error e
23
+ end
24
+ module_function :tick
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ module Bowline
2
+ module Desktop
3
+ module App
4
+ # Methods:
5
+ # busy()
6
+ # exit()
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,97 @@
1
+ module Bowline
2
+ module Desktop
3
+ module Bridge
4
+ module ClassMethods
5
+ # Extend you own classes with this
6
+ # module, and then call js_expose
7
+ # to expose your classes' class
8
+ # variables to JavaScript.
9
+ #
10
+ # Ruby Class:
11
+ # class FooClass
12
+ # extend Bowline::Desktop::Bridge::ClassMethods
13
+ # js_expose
14
+ #
15
+ # def self.foo
16
+ # return :bar
17
+ # end
18
+ # end
19
+ #
20
+ # JavaScript:
21
+ # Bowline.invoke("FooClass", "foo", function(res){
22
+ # console.log(res);
23
+ # })
24
+ def js_expose(opts = {})
25
+ # TODO - implement options,
26
+ # like :except and :only
27
+ instance_eval <<-RUBY
28
+ def js_exposed?
29
+ true
30
+ end
31
+
32
+ def js_invoke(window, method, *args)
33
+ send(method, *args)
34
+ end
35
+ RUBY
36
+ end
37
+ end
38
+
39
+ class Message
40
+ include Bowline::Logging
41
+
42
+ def self.from_array(window, arr)
43
+ arr.map {|i| self.new(window, i) }
44
+ end
45
+
46
+ attr_reader :window, :id, :klass, :method, :args
47
+
48
+ def initialize(window, atts)
49
+ @window = window
50
+ atts = atts.with_indifferent_access
51
+ @id = atts[:id]
52
+ @klass = atts[:klass]
53
+ @method = atts[:method].to_sym
54
+ @args = atts[:args] || []
55
+ end
56
+
57
+ def invoke
58
+ if klass == "_window"
59
+ object = window
60
+ else
61
+ # TODO - security concerns with constantize
62
+ object = klass.constantize
63
+ end
64
+ trace "JS invoking: #{klass}.#{method}(#{args.join(',')})"
65
+ if object.respond_to?(:js_exposed?) && object.js_exposed?
66
+ result = object.js_invoke(window, method, *args)
67
+ proxy = Proxy.new(window)
68
+ proxy.Bowline.invokeCallback(id, result)
69
+ window.run_script(proxy.to_s)
70
+ else
71
+ raise "Method not allowed"
72
+ end
73
+ rescue => e
74
+ log_error e
75
+ end
76
+ end
77
+
78
+ def setup
79
+ Desktop.on_tick(method(:poll))
80
+ end
81
+ module_function :setup
82
+
83
+ def poll
84
+ WindowManager.allocated_windows.each do |window|
85
+ result = window.run_script("try {Bowline.pollJS()} catch(e) {false}")
86
+ next if result.blank? || result == "false"
87
+ result = JSON.parse(result)
88
+ messages = Message.from_array(window, result)
89
+ messages.each(&:invoke)
90
+ end
91
+ rescue => e
92
+ Bowline::Logging.log_error(e)
93
+ end
94
+ module_function :poll
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,9 @@
1
+ module Bowline
2
+ module Desktop
3
+ module Clipboard
4
+ # Methods:
5
+ # write(str)
6
+ # read #=> str
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,28 @@
1
+ module Bowline
2
+ module Desktop
3
+ module Dialog
4
+ def message(msg, options = {})
5
+ style = 0
6
+ style |= YES_NO if options[:yes_no]
7
+ style |= OK if options[:ok]
8
+ style |= CANCEL if options[:cancel]
9
+ style |= ICON_EXCLAMATION if options[:icon_exclamation]
10
+ style |= ICON_HAND if options[:icon_hand]
11
+ style |= ICON_ERROR if options[:icon_error]
12
+ style |= QUESTION if options[:question]
13
+ style |= INFORMATION if options[:information]
14
+ caption = options[:caption] || "Message"
15
+
16
+ result = _message(msg, caption, style)
17
+
18
+ case result
19
+ when YES then :yes
20
+ when NO then :no
21
+ when OK then :ok
22
+ when CANCEL then :cancel
23
+ end
24
+ end
25
+ module_function :message
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,9 @@
1
+ module Bowline
2
+ module Desktop
3
+ module Dock
4
+ # Methods:
5
+ # badge=(str)
6
+ # clear_badge
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module Bowline
2
+ module Desktop
3
+ module Host
4
+ # Methods
5
+ # ip()
6
+ # public_ip()
7
+ # host_name()
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,92 @@
1
+ module Bowline
2
+ module Desktop
3
+ module JS
4
+ class Script
5
+ include Bowline::Logging
6
+
7
+ attr_reader :window, :script, :prok
8
+ def initialize(window, script, prok = nil)
9
+ @window = window
10
+ @script = script
11
+ @prok = prok
12
+ end
13
+ alias :windows :window
14
+
15
+ def ready?
16
+ multiple_windows? ?
17
+ windows.all?(&:loaded?) :
18
+ window.loaded?
19
+ end
20
+
21
+ def call
22
+ if Desktop.enabled?
23
+ trace "JS eval on #{window}: #{script}"
24
+ if multiple_windows?
25
+ windows.each {|w| w.run_script(script) }
26
+ raise "Can't return from multiple windows" if prok
27
+ else
28
+ result = parse(window.run_script(script))
29
+ Thread.new { prok.call(result) } if prok
30
+ end
31
+ result
32
+ else
33
+ trace "Pseudo JS eval on #{window}: #{script}"
34
+ prok.call(nil)
35
+ end
36
+ end
37
+
38
+ private
39
+ def multiple_windows?
40
+ windows.is_a?(Array)
41
+ end
42
+
43
+ def parse(str)
44
+ # This is crazy! The JSON
45
+ # lib can't parse booleans
46
+ case str
47
+ when "true" then true
48
+ when "false" then false
49
+ when nil then nil
50
+ else
51
+ JSON.parse(str)
52
+ end
53
+ end
54
+ end
55
+
56
+ def poll
57
+ run_scripts
58
+ end
59
+ module_function :poll
60
+
61
+ def setup
62
+ Desktop.on_tick(method(:poll))
63
+ end
64
+ module_function :setup
65
+
66
+ def eval(win, str, method = nil, &block)
67
+ script = Script.new(win, str, method||block)
68
+ if Thread.current == Thread.main && script.ready?
69
+ script.call
70
+ else
71
+ scripts << script
72
+ end
73
+ end
74
+ module_function :eval
75
+
76
+ private
77
+ def run_scripts
78
+ ready_scripts = scripts.select(&:ready?)
79
+ while script = ready_scripts.shift
80
+ script.call
81
+ end
82
+ end
83
+ module_function :run_scripts
84
+
85
+ # TODO - thread safety, needs mutex
86
+ def scripts
87
+ Thread.main[:scripts] ||= []
88
+ end
89
+ module_function :scripts
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,9 @@
1
+ module Bowline
2
+ module Desktop
3
+ module Misc
4
+ # Methods:
5
+ # launch_browser(url)
6
+ # bell()
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Bowline
2
+ module Desktop
3
+ class Network
4
+ # Implement address polling to see if we're online
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,94 @@
1
+ module Bowline
2
+ module Desktop
3
+ class Proxy
4
+ # Use to call out to JavaScript.
5
+ #
6
+ # Use the method 'call' if you want
7
+ # to call a function, or the method 'res' if you want
8
+ # the result of a variable evaluation.
9
+ #
10
+ # You can pass a block as the last argument which will
11
+ # be called with the result of the evaluation.
12
+ #
13
+ # All arguments are serialized by JSON, so you can only pass
14
+ # the following objects:
15
+ # * Hash
16
+ # * Array
17
+ # * String
18
+ # * Integer
19
+ #
20
+ # Usage:
21
+ # proxy.FooObject.messages = [1,2,3] #=> "FooObject.messages = [1,2,3]"
22
+ # proxy.FooObject.hi.call #=> "FooObject.hi()"
23
+ # proxy.FooObject.hi(1,2,3).bye.call #=> "FooObject.hi(1,2,3).bye()"
24
+ # proxy.FooObject.messages.res #=> "FooObject.messages"
25
+ # proxy.FooObject.messages.res {|result|
26
+ # puts "Messages are: #{result}"
27
+ # }
28
+ #
29
+ # Reasoning behind this class:
30
+ # * JavaScript needs to be called all at once
31
+ # * We don't know if it's a method call, or a variable
32
+
33
+ def initialize(win)
34
+ @window = win
35
+ @crumbs = []
36
+ end
37
+
38
+ # Call a JavaScript function:
39
+ # proxy.myFunction('arg1').call
40
+ def call(method = nil, &block)
41
+ if @crumbs.empty?
42
+ raise "No method provided"
43
+ end
44
+ string = to_s
45
+ string << "()" unless string.last == ")"
46
+ Bowline::Desktop::JS.eval(
47
+ @window,
48
+ "Bowline.invokeJS(#{string.inspect});",
49
+ method,
50
+ &block
51
+ )
52
+ end
53
+
54
+ # Evaluate a JavaScript variable:
55
+ # proxy.my_variable.res {|result| p result }
56
+ def res(method = nil, &block)
57
+ if @crumbs.empty?
58
+ raise "No attribute provided"
59
+ end
60
+ Bowline::Desktop::JS.eval(
61
+ @window,
62
+ "Bowline.invokeJS(#{to_s.inspect});",
63
+ method,
64
+ &block
65
+ )
66
+ end
67
+
68
+ def method_missing(sym, *args) #:nodoc:
69
+ method_name = sym.to_s
70
+ @crumbs << [method_name, args]
71
+ if method_name.last == "="
72
+ call
73
+ end
74
+ self
75
+ end
76
+
77
+ # Return the JavaScript that is to be evaluated
78
+ def to_s
79
+ (@crumbs || []).inject([]) do |arr, (method, args)|
80
+ str = method
81
+ if args.any?
82
+ str << "(" + args.to_json[1..-2] + ")"
83
+ end
84
+ arr << str
85
+ end.join(".")
86
+ end
87
+ alias :to_js :to_s
88
+
89
+ def inspect
90
+ "<#{self.class.name}:#{@window} #{to_s}>"
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,8 @@
1
+ module Bowline
2
+ module Desktop
3
+ module Sound
4
+ # Methods:
5
+ # play(wav_file_path)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,31 @@
1
+ module Bowline
2
+ module Desktop
3
+ class Window
4
+ include WindowMethods
5
+ # Methods:
6
+ # new()
7
+ # center(direction = :both)
8
+ # close
9
+ # chrome=
10
+ # disable
11
+ # enable
12
+ # file=
13
+ # id
14
+ # modal(flag = true)
15
+ # name=
16
+ # run_script(str) #=> str
17
+ # raise
18
+ # show
19
+ # hide
20
+ # set_size(width, height)
21
+ # set_position(x, y)
22
+ # select_dir(
23
+ # )
24
+ # shown?
25
+ end
26
+
27
+ class MainWindow
28
+ include WindowMethods
29
+ end
30
+ end
31
+ end