bowline 0.4.6 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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