websocket-gui 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0f9b2ada3cef153c8ebd85ff255e143068f21dcd
4
+ data.tar.gz: 0d95a12c9c9fdf239b5f9f4ca26d598766a600cd
5
+ SHA512:
6
+ metadata.gz: b1ba9084cbfcd657ea4e3cda19fbf071ce5497925d2537ca5d219b30b7038eb4c225dfbe4efbb1a7fe753df9721953b8d110a4843fb2a5776e4aed2efe289fc8
7
+ data.tar.gz: 7bf16018e44381dded3b25ea882ed0155d9339b6bdc631ff832ec8c8078ae9e927ab04270d47150dfbbe2f8e0d031225c075e71be51a49207d4b8a7c5ccc05f5
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.swp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jason
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,143 @@
1
+ # Websocket Gui
2
+ This gem uses Sinatra, EventMachine, and Web Sockets to make it easy to use the browser as a GUI for Ruby apps that
3
+ would otherwise be stuck in the console.
4
+
5
+
6
+ ## Using Websocket Gui
7
+ To use this gem, make a class that extends WebsocketGui::Base and a HTML/JS file to serve as the GUI.
8
+
9
+
10
+ ### Configuration
11
+ The following configuration options are available:
12
+ :socket_port (8080)
13
+ :socket_host (127.0.0.1)
14
+ :http_port (3000)
15
+ :http_host (127.0.0.1)
16
+ :view (:index)
17
+ :tick_interval (nil)
18
+
19
+ The options can be set in several ways, each level overriding the previous:
20
+ 1 In declaring your subclass of WebsocketGui::Base (like tick\_interval below)
21
+ 1 By passing an options hash to the initializer
22
+ 1 By passing an options hash to the run! method
23
+
24
+
25
+ ### project-root/app.rb
26
+ require 'websocket-gui'
27
+
28
+ class App < WebsocketGui::Base
29
+
30
+ # specify the name of the file containing the HTML of the app (this is a single-page app)
31
+ # ex. Look in root directory for frontendfile.erb instead of index.erb (which is the default)
32
+ #view :frontendfile
33
+
34
+ # set the time (seconds) between calls to 'on_tick'
35
+ # if nil (default), on_tick will not fire
36
+ tick_interval 0.1
37
+
38
+ # code for the on_tick event
39
+ on_tick do |connected|
40
+ @tick_block.call(connected)
41
+ end
42
+
43
+ # code for the on_socket_open event
44
+ on_socket_open do |handshake|
45
+ socket_send "Welcome!!!"
46
+ puts "Client connection opened:"
47
+ puts "#{handshake.inspect}"
48
+ end
49
+
50
+ # code for the on_socket_recv event
51
+ on_socket_recv do |msg|
52
+ puts "Received message from client: #{msg.strip}"
53
+ socket_send "I received your message: #{msg.strip}"
54
+ end
55
+
56
+ # code for the on_socket_close event
57
+ on_socket_close do
58
+ puts "Socket closed."
59
+ end
60
+ end
61
+
62
+ # specify options in the constructor and/or the run method.
63
+ instance = App.new http_port: 3000, http_host: '127.0.0.1'
64
+ instance.run! socket_port: 8080, socket_host: '127.0.0.1'
65
+
66
+
67
+
68
+ ### project-root/index.erb
69
+
70
+ <!doctype html>
71
+ <html>
72
+ <head>
73
+ <title>Test Web Sockets</title>
74
+ <meta charset="utf-8" />
75
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
76
+ </head>
77
+
78
+ <body>
79
+ <div id="connectedContainer" style="display:none;">
80
+ <textarea id="input"></textarea>
81
+ <input type="button" id="send" value="Send" />
82
+
83
+ <ul id="output"></ul>
84
+ <input type="button" id="disconnect" value="Disconnect" />
85
+ </div>
86
+ <div id="notConnectedContainer">
87
+ <input type="button" id="connect" value="Connect" />
88
+ </div>
89
+ <script type="text/javascript">
90
+ var socket;
91
+ var connect = function () {
92
+ socket = new WebSocket("ws://localhost:8080");
93
+ var writeMessage = function (msg) {
94
+ $("<li></li>").text (msg).appendTo ($("#output"));
95
+ };
96
+ socket.onmessage = function (evt) {
97
+ writeMessage (evt.data);
98
+ };
99
+ socket.onclose = function () {
100
+ writeMessage ("Socket Closed!");
101
+ $("#connectedContainer").hide ();
102
+ $("#notConnectedContainer").show();
103
+ $("#output li").remove ();
104
+ }
105
+ socket.onopen = function () {
106
+ writeMessage ("Socket Opened!");
107
+ $("#connectedContainer").show ();
108
+ $("#notConnectedContainer").hide ();
109
+ }
110
+ $("#send").on ('click', function () {
111
+ var input = $("#input");
112
+ if (input.val ())
113
+ {
114
+ socket.send(input.val ());
115
+ input.val ('');
116
+ }
117
+ });
118
+ }
119
+ $("#connect").on ('click', function () { connect (); } );
120
+ $("#disconnect").on ('click', function () { socket.close (); });
121
+
122
+ </script>
123
+ </body>
124
+ </html>
125
+
126
+
127
+ ## file structure
128
+ project-root/
129
+ app.rb
130
+ index.erb
131
+ ... (up to you)
132
+
133
+
134
+ ## running the app (from the project dir)
135
+ $ ruby app.rb
136
+
137
+ This will start the socket server and sinatra, and launch a browser with your view.
138
+
139
+
140
+ ## todo
141
+ * Create a small JS library that wraps the native websocket and makes it easy to post events to the server.
142
+ * Expand event handlers so you can write events like `on_start do |params|` instead of having to do parse raw strings and do everything in on\_socket\_recv
143
+
data/Rakefile ADDED
@@ -0,0 +1,69 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'date'
5
+
6
+ #################################################################################
7
+ #
8
+ # Some utilities to find out info about the package
9
+ #
10
+ #################################################################################
11
+
12
+ def name
13
+ @name ||= Dir['*.gemspec'].first.split('.').first
14
+ end
15
+
16
+ def version
17
+ line = File.read("lib/#{name}/version.rb")[/^\s*VERSION\s*=\s*.*/]
18
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
19
+ end
20
+
21
+ def gemspec_file
22
+ "#{name}.gemspec"
23
+ end
24
+
25
+ def gem_file
26
+ "pkg/#{name}-#{version}.gem"
27
+ end
28
+
29
+ #################################################################################
30
+ #
31
+ # Tasks
32
+ #
33
+ #################################################################################
34
+
35
+ desc "Run the tests"
36
+ task :default => :spec
37
+
38
+ require 'rspec/core/rake_task'
39
+ RSpec::Core::RakeTask.new(:spec)
40
+
41
+ desc "Build gem locally"
42
+ task :build => :validate do
43
+ system "gem build #{name}.gemspec"
44
+ FileUtils.mkdir_p "pkg"
45
+ FileUtils.mv "#{name}-#{version}.gem", gem_file
46
+ end
47
+
48
+ desc "Publish the gem to rubygems.org"
49
+ task :publish => :build do
50
+ system "gem push #{gem_file}"
51
+ end
52
+
53
+ desc "Install gem locally"
54
+ task :install => :build do
55
+ system "gem install #{gem_file}"
56
+ end
57
+
58
+ desc "Validate #{gemspec_file}"
59
+ task :validate do
60
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
61
+ unless libfiles.empty?
62
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
63
+ exit!
64
+ end
65
+ unless Dir['VERSION*'].empty?
66
+ puts "A `VERSION` file at root level violates Gem best practices."
67
+ exit!
68
+ end
69
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path('../../lib/websocket-gui', __FILE__)
2
+
3
+ class ExampleWebSocketApp < WebsocketGui::Base
4
+
5
+ tick_interval 5
6
+
7
+ on_tick do |connected|
8
+ puts "Tick: " + (connected ? "connected" : "not connected")
9
+ socket_send "Tick"
10
+ end
11
+
12
+ on_socket_open do |handshake|
13
+ socket_send "Socket opened. Welcome!!!"
14
+ puts "Client connection opened.\n Handshake:\n #{handshake.inspect}"
15
+ end
16
+
17
+ on_socket_recv do |msg|
18
+ puts "Received message from client: #{msg.strip}"
19
+ socket_send "I received your message: #{msg.strip}"
20
+ end
21
+
22
+ on_socket_close do
23
+ puts "Socket closed."
24
+ end
25
+ end
26
+
27
+ if __FILE__ == $0
28
+ example = ExampleWebSocketApp.new
29
+ example.run!
30
+ end
@@ -0,0 +1,63 @@
1
+ <!doctype html>
2
+
3
+ <html>
4
+
5
+ <head>
6
+ <title>Test Web Sockets</title>
7
+ <meta charset="utf-8" />
8
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
9
+ <style type="text/css">
10
+
11
+ </style>
12
+ </head>
13
+
14
+ <body>
15
+ <div id="connectedContainer" style="display:none;">
16
+ <textarea id="input"></textarea>
17
+ <input type="button" id="send" value="Send" />
18
+
19
+ <ul id="output"></ul>
20
+ <input type="button" id="disconnect" value="Disconnect" />
21
+ </div>
22
+ <div id="notConnectedContainer">
23
+ <input type="button" id="connect" value="Connect" />
24
+ </div>
25
+
26
+ <script type="text/javascript">
27
+ var socket;
28
+ var connect = function () {
29
+ socket = new WebSocket("ws://localhost:8080");
30
+ var writeMessage = function (msg) {
31
+ $("<li></li>").text (msg).appendTo ($("#output"));
32
+ };
33
+ socket.onmessage = function (evt) {
34
+ writeMessage (evt.data);
35
+ };
36
+ socket.onclose = function () {
37
+ writeMessage ("Socket Closed!");
38
+ $("#connectedContainer").hide ();
39
+ $("#notConnectedContainer").show();
40
+ $("#output li").remove ();
41
+ }
42
+ socket.onopen = function () {
43
+ writeMessage ("Socket Opened!");
44
+ $("#connectedContainer").show ();
45
+ $("#notConnectedContainer").hide ();
46
+ }
47
+ $("#send").on ('click', function () {
48
+ var input = $("#input");
49
+ if (input.val ())
50
+ {
51
+ socket.send(input.val ());
52
+ input.val ('');
53
+ }
54
+ });
55
+ }
56
+
57
+ $("#connect").on ('click', function () { connect (); } );
58
+ $("#disconnect").on ('click', function () { socket.close (); });
59
+
60
+ </script>
61
+ </body>
62
+
63
+ </html>
@@ -0,0 +1,79 @@
1
+ module WebsocketGui
2
+
3
+ class Base
4
+
5
+ # class-level config, so you can wire your settings into your class
6
+ # These can also be provided when calling run!
7
+ @@config = {
8
+ socket_port: 8080,
9
+ socket_host: '127.0.0.1',
10
+ http_port: 3000,
11
+ http_host: '127.0.0.1',
12
+ tick_interval: nil,
13
+ view: :index,
14
+ }
15
+ def self.method_missing(method, *args, &block)
16
+ if block_given?
17
+ @@config[method] = block
18
+ else
19
+ @@config[method] = args.first
20
+ end
21
+ end
22
+
23
+ attr_reader :config
24
+
25
+ def initialize(config = {})
26
+ @config = @@config.merge(config)
27
+ end
28
+
29
+ # start the socket server and the web server, and launch a browser to fetch the view from the web server
30
+ def run!(runtime_config = {})
31
+ @config.merge! runtime_config
32
+
33
+ EM.run do
34
+ if @config[:tick_interval]
35
+ EM.add_periodic_timer(@config[:tick_interval]) do
36
+ socket_trigger(:on_tick, @socket_connected)
37
+ end
38
+ end
39
+
40
+ EventMachine::WebSocket.run(host: @config[:socket_host], port: @config[:socket_port]) do |socket|
41
+ @socket_active = socket
42
+ socket.onopen do |handshake|
43
+ @socket_connected = true
44
+ socket_trigger(:on_socket_open, handshake)
45
+ end
46
+
47
+ socket.onmessage do |msg|
48
+ socket_trigger(:on_socket_recv, msg)
49
+ end
50
+
51
+ socket.onclose do
52
+ socket_trigger(:on_socket_close)
53
+ @socket_connected = false
54
+ end
55
+ end
56
+
57
+ Launchy.open("http://#{@config[:http_host]}:#{@config[:http_port]}/")
58
+ WebsocketGui::SinatraWrapper.view_path = @config[:view]
59
+ WebsocketGui::SinatraWrapper.run!(
60
+ port: @config[:http_port],
61
+ bind: @config[:http_host])
62
+ end
63
+ end
64
+
65
+ def socket_send(msg)
66
+ @socket_active.send msg if @socket_connected
67
+ end
68
+
69
+ def socket_close
70
+ @socket_active.stop if @socket_connected
71
+ end
72
+
73
+ private
74
+
75
+ def socket_trigger(method, *args)
76
+ self.instance_exec(*args, &@config[method]) if @config[method].kind_of? Proc
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,18 @@
1
+ module WebsocketGui
2
+ class SinatraWrapper < Sinatra::Base
3
+
4
+ set :views, './'
5
+
6
+ get '/' do
7
+ erb self.class.view_path
8
+ end
9
+
10
+ def self.view_path
11
+ @view_path || :index
12
+ end
13
+
14
+ def self.view_path=(view_path)
15
+ @view_path = view_path.to_sym
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module WebsocketGui
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,10 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require "em-websocket"
4
+ require "sinatra"
5
+ require "thin"
6
+ require "launchy"
7
+
8
+ require "websocket-gui/base"
9
+ require "websocket-gui/sinatra_wrapper"
10
+
data/spec/base_spec.rb ADDED
@@ -0,0 +1,44 @@
1
+ # the example loads dependencies AND gives us an example class to test
2
+ require File.expand_path('../../examples/example', __FILE__)
3
+
4
+ describe ExampleWebSocketApp do
5
+
6
+ it { should respond_to(:run!) }
7
+ it { should respond_to(:socket_send) }
8
+ it { should respond_to(:socket_close) }
9
+ its(:config) { should be_an_instance_of(Hash) }
10
+
11
+ context "override Base defaults" do
12
+ let(:example) {
13
+ ExampleWebSocketApp.new(http_port: 80, http_host: "localhost")
14
+ }
15
+ let(:config) { example.config }
16
+
17
+ it "has defaults inherited from Base" do
18
+ config[:socket_port].should equal(8080)
19
+ config[:socket_host].should match('127.0.0.1')
20
+ end
21
+
22
+ it "overrides defaults in subclass definition" do
23
+ config[:tick_interval].should equal(5)
24
+ config[:on_tick].should be_a_kind_of(Proc)
25
+ end
26
+
27
+ it "overrides defaults in constructor" do
28
+ config[:http_port].should equal(80)
29
+ config[:http_host].should match('localhost')
30
+ end
31
+ end
32
+
33
+ context "override subclass defaults" do
34
+ let(:example) {
35
+ ExampleWebSocketApp.new(tick_interval: 1)
36
+ }
37
+ let(:config) { example.config }
38
+
39
+ it "overrides already overridden defaults in constructor" do
40
+ config[:tick_interval].should equal(1)
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,18 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
18
+
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'websocket-gui/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "websocket-gui"
8
+ spec.version = WebsocketGui::VERSION
9
+ spec.authors = ["Jason Pollentier"]
10
+ spec.email = ["pollentj@gmail.com"]
11
+ spec.description = %q{Use Sinatra, Websockets, and EventMachine to create
12
+ an event-based GUI for Ruby projects that would otherwise be stuck in the console.
13
+ }
14
+ spec.summary = %q{Use the browser as a GUI for local Ruby apps.}
15
+ spec.homepage = ""
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.required_ruby_version = '~> 2.0'
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_runtime_dependency 'em-websocket', '~> 0.5.0'
28
+ spec.add_runtime_dependency 'sinatra', '~> 1.4.3'
29
+ spec.add_runtime_dependency 'thin', '>= 1.5.1'
30
+ spec.add_runtime_dependency 'launchy', '~> 2.3.0'
31
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: websocket-gui
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jason Pollentier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: em-websocket
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.5.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.5.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: sinatra
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 1.4.3
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 1.4.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: thin
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: 1.5.1
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.5.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: launchy
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 2.3.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 2.3.0
111
+ description: |
112
+ Use Sinatra, Websockets, and EventMachine to create
113
+ an event-based GUI for Ruby projects that would otherwise be stuck in the console.
114
+ email:
115
+ - pollentj@gmail.com
116
+ executables: []
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - .gitignore
121
+ - .rspec
122
+ - Gemfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - examples/example.rb
127
+ - examples/index.erb
128
+ - lib/websocket-gui.rb
129
+ - lib/websocket-gui/base.rb
130
+ - lib/websocket-gui/sinatra_wrapper.rb
131
+ - lib/websocket-gui/version.rb
132
+ - spec/base_spec.rb
133
+ - spec/spec_helper.rb
134
+ - websocket-gui.gemspec
135
+ homepage: ''
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ~>
146
+ - !ruby/object:Gem::Version
147
+ version: '2.0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 2.0.7
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: Use the browser as a GUI for local Ruby apps.
159
+ test_files:
160
+ - spec/base_spec.rb
161
+ - spec/spec_helper.rb