bowl 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +23 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +66 -0
- data/LICENSE.txt +22 -0
- data/README.md +25 -0
- data/Rakefile +1 -0
- data/bin/bowl_start +23 -0
- data/bowl.gemspec +31 -0
- data/lib/bowl.rb +5 -0
- data/lib/bowl/app/Procfile +1 -0
- data/lib/bowl/app/bootstrap.rb +13 -0
- data/lib/bowl/app/config.ru +20 -0
- data/lib/bowl/app/controllers/css.rb +3 -0
- data/lib/bowl/app/controllers/js.rb +17 -0
- data/lib/bowl/app/controllers/main.rb +25 -0
- data/lib/bowl/app/controllers/webpage.rb +14 -0
- data/lib/bowl/app/helpers/helper.rb +14 -0
- data/lib/bowl/app/helpers/plugins.rb +20 -0
- data/lib/bowl/app/js/bowl.js +41 -0
- data/lib/bowl/app/libs/error.rb +3 -0
- data/lib/bowl/app/libs/plugins.rb +104 -0
- data/lib/bowl/app/plugins/arduino.rb +17 -0
- data/lib/bowl/app/plugins/mac-say.rb +12 -0
- data/lib/bowl/app/plugins/webbrowser.rb +12 -0
- data/lib/bowl/app/public/css/bootstrap-responsive.min.css +9 -0
- data/lib/bowl/app/public/css/bootstrap.min.css +9 -0
- data/lib/bowl/app/public/img/glyphicons-halflings-white.png +0 -0
- data/lib/bowl/app/public/img/glyphicons-halflings.png +0 -0
- data/lib/bowl/app/public/js/bootstrap.min.js +6 -0
- data/lib/bowl/app/public/js/jquery.js +2 -0
- data/lib/bowl/app/views/index.haml +14 -0
- data/lib/bowl/app/views/layout.haml +32 -0
- data/lib/bowl/app/views/main.scss +4 -0
- data/lib/bowl/app/views/plugin.haml +62 -0
- data/lib/bowl/app/views/plugins.haml +28 -0
- data/lib/bowl/version.rb +3 -0
- metadata +275 -0
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
.DS_Store
|
2
|
+
*.tmp
|
3
|
+
*~
|
4
|
+
*#*
|
5
|
+
vendor
|
6
|
+
.sass-cache
|
7
|
+
.bundle
|
8
|
+
config.yml
|
9
|
+
*.gem
|
10
|
+
*.rbc
|
11
|
+
.config
|
12
|
+
.yardoc
|
13
|
+
InstalledFiles
|
14
|
+
_yardoc
|
15
|
+
coverage
|
16
|
+
doc/
|
17
|
+
lib/bundler/man
|
18
|
+
pkg
|
19
|
+
rdoc
|
20
|
+
spec/reports
|
21
|
+
test/tmp
|
22
|
+
test/version_tmp
|
23
|
+
tmp
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
bowl (0.0.1)
|
5
|
+
arduino_firmata
|
6
|
+
args_parser (> 0.1.0)
|
7
|
+
eventmachine
|
8
|
+
haml
|
9
|
+
hashie
|
10
|
+
json
|
11
|
+
rack
|
12
|
+
sass
|
13
|
+
sinatra (> 1.3.0)
|
14
|
+
sinatra-cometio
|
15
|
+
sinatra-contrib (> 1.3.0)
|
16
|
+
thin
|
17
|
+
|
18
|
+
GEM
|
19
|
+
remote: https://rubygems.org/
|
20
|
+
specs:
|
21
|
+
arduino_firmata (0.1.6)
|
22
|
+
args_parser (>= 0.1.2, < 1.0.0)
|
23
|
+
serialport (>= 1.1.0, < 2.0.0)
|
24
|
+
args_parser (0.1.2)
|
25
|
+
backports (2.6.5)
|
26
|
+
daemons (1.1.9)
|
27
|
+
event_emitter (0.1.0)
|
28
|
+
eventmachine (1.0.0)
|
29
|
+
haml (3.1.7)
|
30
|
+
hashie (1.2.0)
|
31
|
+
json (1.7.5)
|
32
|
+
rack (1.4.1)
|
33
|
+
rack-protection (1.2.0)
|
34
|
+
rack
|
35
|
+
rack-test (0.6.2)
|
36
|
+
rack (>= 1.0)
|
37
|
+
sass (3.2.3)
|
38
|
+
serialport (1.1.0)
|
39
|
+
sinatra (1.3.3)
|
40
|
+
rack (~> 1.3, >= 1.3.6)
|
41
|
+
rack-protection (~> 1.2)
|
42
|
+
tilt (~> 1.3, >= 1.3.3)
|
43
|
+
sinatra-cometio (0.0.8)
|
44
|
+
event_emitter (>= 0.1.0)
|
45
|
+
eventmachine (>= 1.0.0)
|
46
|
+
json (>= 1.7.0)
|
47
|
+
sinatra (>= 1.3.3)
|
48
|
+
sinatra-contrib (>= 1.3.2)
|
49
|
+
sinatra-contrib (1.3.2)
|
50
|
+
backports (>= 2.0)
|
51
|
+
eventmachine
|
52
|
+
rack-protection
|
53
|
+
rack-test
|
54
|
+
sinatra (~> 1.3.0)
|
55
|
+
tilt (~> 1.3)
|
56
|
+
thin (1.5.0)
|
57
|
+
daemons (>= 1.0.9)
|
58
|
+
eventmachine (>= 0.12.6)
|
59
|
+
rack (>= 1.0.0)
|
60
|
+
tilt (1.3.3)
|
61
|
+
|
62
|
+
PLATFORMS
|
63
|
+
ruby
|
64
|
+
|
65
|
+
DEPENDENCIES
|
66
|
+
bowl!
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Sho Hashimoto
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Bowl
|
2
|
+
|
3
|
+
Bowl is a Mac/Linux controller for your Application.
|
4
|
+
Write Ruby Code, put it into plug-in directory. Bowl automatically generate sample code and Web UI.
|
5
|
+
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
% gem install bowl
|
10
|
+
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
% bowl_start -port 8901
|
15
|
+
|
16
|
+
=> start server - http://localhost:8901
|
17
|
+
|
18
|
+
|
19
|
+
## Contributing
|
20
|
+
|
21
|
+
1. Fork it
|
22
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
23
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
24
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
25
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/bowl_start
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'args_parser'
|
4
|
+
|
5
|
+
parser = ArgsParser.parse ARGV do
|
6
|
+
arg :port, 'HTTP port', :alias => :p, :default => 8901
|
7
|
+
arg :help, 'show help', :alias => :h
|
8
|
+
end
|
9
|
+
bin = $0.split('/').last
|
10
|
+
|
11
|
+
if parser.has_option? :help
|
12
|
+
STDERR.puts "Bowl - http://github.com/shokai/bowl"
|
13
|
+
STDERR.puts
|
14
|
+
STDERR.puts parser.help
|
15
|
+
STDERR.puts
|
16
|
+
STDERR.puts "e.g."
|
17
|
+
STDERR.puts " % #{bin} --port 8901"
|
18
|
+
exit 0
|
19
|
+
end
|
20
|
+
|
21
|
+
dir = File.expand_path '../lib/bowl/app', File.dirname(__FILE__)
|
22
|
+
puts "start bowl => http://localhost:#{parser[:port]}"
|
23
|
+
system "cd '#{dir}' && rackup config.ru -p #{parser[:port]}"
|
data/bowl.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'bowl/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "bowl"
|
7
|
+
gem.version = Bowl::VERSION
|
8
|
+
gem.authors = ["Sho Hashimoto"]
|
9
|
+
gem.email = ["hashimoto@shokai.org"]
|
10
|
+
gem.description = %q{Bowl is a Mac/Linux controller for your Application.}
|
11
|
+
gem.summary = %q{Write Ruby Code, put it into plug-in directory. Bowl automatically generate sample code and Web UI.}
|
12
|
+
gem.homepage = "https://github.com/shokai/bowl"
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
|
19
|
+
gem.add_dependency 'rack'
|
20
|
+
gem.add_dependency 'sinatra', '> 1.3.0'
|
21
|
+
gem.add_dependency 'eventmachine'
|
22
|
+
gem.add_dependency 'thin'
|
23
|
+
gem.add_dependency 'sinatra-contrib', '> 1.3.0'
|
24
|
+
gem.add_dependency 'sinatra-cometio'
|
25
|
+
gem.add_dependency 'json'
|
26
|
+
gem.add_dependency 'haml'
|
27
|
+
gem.add_dependency 'sass'
|
28
|
+
gem.add_dependency 'hashie'
|
29
|
+
gem.add_dependency 'args_parser', '> 0.1.0'
|
30
|
+
gem.add_dependency 'arduino_firmata'
|
31
|
+
end
|
data/lib/bowl.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
web: bundle exec rackup config.ru -p $PORT
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rack'
|
4
|
+
require 'sinatra'
|
5
|
+
$stdout.sync = true if development?
|
6
|
+
require 'sinatra/reloader' if development?
|
7
|
+
require 'sinatra/content_for'
|
8
|
+
require 'sinatra/cometio'
|
9
|
+
require 'json'
|
10
|
+
require 'haml'
|
11
|
+
require 'sass'
|
12
|
+
require 'event_emitter'
|
13
|
+
require 'hashie'
|
14
|
+
require 'fileutils'
|
15
|
+
require File.dirname(__FILE__)+'/bootstrap'
|
16
|
+
Bootstrap.init :libs, :helpers, :controllers
|
17
|
+
|
18
|
+
set :haml, :escape_html => true
|
19
|
+
|
20
|
+
run Sinatra::Application
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
helpers do
|
3
|
+
def bowl_js
|
4
|
+
"#{app_root}/bowl.js"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
get '/bowl.js' do
|
9
|
+
content_type 'application/javascript'
|
10
|
+
@js ||= (
|
11
|
+
js = nil
|
12
|
+
File.open(File.expand_path '../js/bowl.js', File.dirname(__FILE__)) do |f|
|
13
|
+
js = f.read
|
14
|
+
end
|
15
|
+
ERB.new(js).result(binding)
|
16
|
+
)
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
before '/*.json' do
|
2
|
+
content_type 'application/json'
|
3
|
+
end
|
4
|
+
|
5
|
+
before '/*' do
|
6
|
+
@title = 'Bowl'
|
7
|
+
end
|
8
|
+
|
9
|
+
get '/' do
|
10
|
+
haml :index
|
11
|
+
end
|
12
|
+
|
13
|
+
get '/plugins' do
|
14
|
+
@title = "Plug-ins"
|
15
|
+
haml :plugins
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/plugin/:name' do
|
19
|
+
name = params['name']
|
20
|
+
halt 404, "plugin \"#{name}\" not found" unless plugins.has_key? name
|
21
|
+
@plugin = plugins[name]
|
22
|
+
@title = "plugin/#{name}"
|
23
|
+
halt 500, "Error : #{@plugin.message} at #{Plugin.list[name]}" if @plugin.kind_of? Error
|
24
|
+
haml :plugin
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
def plugins
|
3
|
+
@@plugins ||=
|
4
|
+
(
|
5
|
+
plugins = {}
|
6
|
+
Plugin.list.each do |name, path|
|
7
|
+
puts "load plugin \"#{name}\" - #{path}"
|
8
|
+
begin
|
9
|
+
plugins[name] = Plugin.new name
|
10
|
+
rescue => e
|
11
|
+
STDERR.puts e
|
12
|
+
plugins[name] = e
|
13
|
+
next
|
14
|
+
end
|
15
|
+
end
|
16
|
+
plugins
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
plugins
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
var bowl = new (function(){
|
3
|
+
var self = this;
|
4
|
+
this.io = null;
|
5
|
+
|
6
|
+
this.load_script_tag = function(url, onload){
|
7
|
+
var script = document.createElement("script");
|
8
|
+
script.src = url;
|
9
|
+
if(typeof onload === "function"){
|
10
|
+
script.onload = onload;
|
11
|
+
script.onreadystatechange = function(){
|
12
|
+
if(readyState=="loaded" || readyState=="complete"){
|
13
|
+
onload();
|
14
|
+
}
|
15
|
+
};
|
16
|
+
}
|
17
|
+
document.body.appendChild(script);
|
18
|
+
};
|
19
|
+
|
20
|
+
this.init = function(){
|
21
|
+
self.load_script_tag("<%= cometio_js %>", function(){
|
22
|
+
self.io = new CometIO().connect();
|
23
|
+
self.io.on("connect", function(session_id){
|
24
|
+
console.log("bowl connect : "+session_id);
|
25
|
+
});
|
26
|
+
});
|
27
|
+
};
|
28
|
+
|
29
|
+
this.plugin = function(name, data, callback){
|
30
|
+
if(typeof callback === "function"){
|
31
|
+
var callback_name = "plugin_"+name+'_callback_'+Date.now();
|
32
|
+
self.io.once(callback_name, callback);
|
33
|
+
data["__callback"] = callback_name;
|
34
|
+
}
|
35
|
+
self.io.push("plugin_"+name, data);
|
36
|
+
};
|
37
|
+
})();
|
38
|
+
|
39
|
+
$(function(){
|
40
|
+
bowl.init();
|
41
|
+
});
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class Plugin
|
2
|
+
|
3
|
+
def self.dirs
|
4
|
+
@@dirs
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.dirs
|
8
|
+
@@dirs ||= [File.expand_path('../plugins', File.dirname(__FILE__)),
|
9
|
+
"#{ENV['HOME']}/.bowl/plugins"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.list
|
13
|
+
@@list ||=
|
14
|
+
(
|
15
|
+
h = {}
|
16
|
+
self.dirs.each do |d|
|
17
|
+
FileUtils.mkdir_p d unless File.exists? d
|
18
|
+
Dir.glob(File.expand_path '*.rb', d).each do |rb|
|
19
|
+
name = rb.scan(/([^\/]+)\.rb$/)[0][0]
|
20
|
+
h[name] = rb
|
21
|
+
end
|
22
|
+
end
|
23
|
+
h
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
include EventEmitter
|
28
|
+
attr_reader :name, :fields
|
29
|
+
|
30
|
+
def initialize(name)
|
31
|
+
@name = name
|
32
|
+
@meta = {}
|
33
|
+
@options = Hash.new(false)
|
34
|
+
@fields = Hash.new{|h,k|
|
35
|
+
h[k] = {
|
36
|
+
:name => nil,
|
37
|
+
:index => lambda{ @fields.keys.size }.call,
|
38
|
+
:type => String,
|
39
|
+
:default => nil,
|
40
|
+
:value => nil
|
41
|
+
}
|
42
|
+
}
|
43
|
+
__code = nil
|
44
|
+
open(self.class.list[name]) do |f|
|
45
|
+
__code = f.read
|
46
|
+
end
|
47
|
+
raise IOError, "cannot read plug-in file \"#{name}\"" unless __code
|
48
|
+
instance_eval __code
|
49
|
+
end
|
50
|
+
|
51
|
+
def meta(meta=nil)
|
52
|
+
if meta.kind_of? Hash
|
53
|
+
@meta = meta
|
54
|
+
else
|
55
|
+
return @meta
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def set(k,v)
|
60
|
+
@options[k.to_sym] = v
|
61
|
+
end
|
62
|
+
|
63
|
+
def get(k)
|
64
|
+
@options[k.to_sym]
|
65
|
+
end
|
66
|
+
|
67
|
+
def data(&block)
|
68
|
+
raise ArgumentError, 'block not given' unless block_given?
|
69
|
+
instance_eval &block
|
70
|
+
end
|
71
|
+
|
72
|
+
def call(&block)
|
73
|
+
raise ArgumentError, 'block not given' unless block_given?
|
74
|
+
this = self
|
75
|
+
CometIO.on "plugin_#{name}" do |data, session_id|
|
76
|
+
this.fields.each do |name, field|
|
77
|
+
data[name] = field[:default] if field[:default] and data[name].to_s.empty?
|
78
|
+
end
|
79
|
+
this.instance_variables.each do |name|
|
80
|
+
name = name.to_s.gsub(/^@/,'')
|
81
|
+
next if ['meta','fields'].include? name
|
82
|
+
data[name] = this.instance_eval "@#{name}"
|
83
|
+
end
|
84
|
+
h = Hashie::Mash.new(data)
|
85
|
+
if this.get :callback
|
86
|
+
def h.callback(data)
|
87
|
+
CometIO.push __callback, data if __callback.to_s.size > 0
|
88
|
+
end
|
89
|
+
end
|
90
|
+
h.instance_eval &block
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def field(name, params={})
|
95
|
+
if Hashie::Mash.instance_methods.include? name.to_sym
|
96
|
+
raise ArgumentError, "field \"#{name}\" is reserved."
|
97
|
+
end
|
98
|
+
fields[name][:name] = name
|
99
|
+
params.each do |k,v|
|
100
|
+
fields[name][k] = v
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|