web-repl 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.
- data/LICENSE +13 -0
- data/README.md +66 -0
- data/bin/web-repl +16 -0
- data/js/replConnection-0.1.min.js +1 -0
- data/js/replConnection.js +117 -0
- data/lib/web-repl.rb +22 -0
- data/lib/web-repl/messager.rb +48 -0
- data/lib/web-repl/patch.rb +39 -0
- data/lib/web-repl/repl.rb +128 -0
- data/test/helper.rb +8 -0
- data/test/messager_test.rb +88 -0
- data/test/repl_test.rb +14 -0
- metadata +140 -0
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2014 Ari Russo
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# web-repl
|
2
|
+
|
3
|
+
This is a Javascript [REPL](http://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) that runs in Ruby. Evaluation is done by a web browser instance.
|
4
|
+
|
5
|
+
One use of this is to control the Chrome Developer Console remotely.
|
6
|
+
|
7
|
+
#### Background
|
8
|
+
|
9
|
+
I was working on a toy program recently that needed the browser to be in full screen mode, which made using the regular Chrome console very difficult to use. I came up with this program as an alternative.
|
10
|
+
|
11
|
+
There are similar tools that run in nodejs for example but since my program uses a Ruby backend anyway, this is convenient for me.
|
12
|
+
|
13
|
+
It communicates over websocket.
|
14
|
+
|
15
|
+
There is basically no attention to security here, so please use at your own discretion.
|
16
|
+
|
17
|
+
#### Usage
|
18
|
+
|
19
|
+
###### Browser
|
20
|
+
|
21
|
+
To enable the browser side of this, include something like this in the head of your webpage:
|
22
|
+
|
23
|
+
```html
|
24
|
+
<script src="js/replConnection.js"></script>
|
25
|
+
<script type="text/javascript">
|
26
|
+
window.onload = function() {
|
27
|
+
var repl = new ReplConnection("localhost", 9007, { debug: true, reconnect: true });
|
28
|
+
repl.start();
|
29
|
+
}
|
30
|
+
</script>
|
31
|
+
```
|
32
|
+
|
33
|
+
The javascript assets for this project are located in the [/js directory](https://github.com/arirusso/web-repl/tree/master/js).
|
34
|
+
|
35
|
+
There is also a full example of a webpage (with [rack](http://rack.github.io/) configuration) in the [/examples/page directory](https://github.com/arirusso/web-repl/tree/master/examples/page)
|
36
|
+
|
37
|
+
###### REPL
|
38
|
+
|
39
|
+
The REPL can be used either in a Ruby program/console or there is a "binary" Ruby script.
|
40
|
+
|
41
|
+
In Ruby the usage looks like this:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
require "web-repl"
|
45
|
+
|
46
|
+
WebRepl.start(:host => "localhost", :port => 9007)
|
47
|
+
```
|
48
|
+
|
49
|
+
You can see an explanation of background usage here.
|
50
|
+
|
51
|
+
To use this as a script, run this from the command line. (The script should install with the gem)
|
52
|
+
|
53
|
+
web-repl localhost:9007
|
54
|
+
|
55
|
+
#### Installation
|
56
|
+
|
57
|
+
gem install web-repl
|
58
|
+
|
59
|
+
or with Bundler
|
60
|
+
|
61
|
+
gem "web-repl"
|
62
|
+
|
63
|
+
#### License
|
64
|
+
|
65
|
+
Licensed under Apache 2.0, See the file LICENSE
|
66
|
+
Copyright (c) 2014 [Ari Russo](http://arirusso.com)
|
data/bin/web-repl
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require "optparse"
|
5
|
+
require "web-repl"
|
6
|
+
|
7
|
+
ARGV[0]
|
8
|
+
|
9
|
+
raise OptionParser::MissingArgument if ARGV[0].nil?
|
10
|
+
|
11
|
+
host, port = *ARGV[0].scan(/(\w+):(\d{4,})/)[0]
|
12
|
+
|
13
|
+
raise OptionParser::MissingArgument if host.nil? || port.nil?
|
14
|
+
|
15
|
+
WebRepl.start(:host => host, :port => port)
|
16
|
+
exit 0
|
@@ -0,0 +1 @@
|
|
1
|
+
function ReplConnection(e,t,n){if(n===null){n={}}this.debug=!!n.debug;this.reconnect=!!n.reconnect;this.retryTime=n.retryTime||1e3;this.onReceive=n.onReceive;this.host=e;this.port=t;this.active=false;this.socket;this.supported="WebSocket"in window;if(this.supported){console.log("REPL: socket ok")}else{console.log("REPL: socket not supported")}}ReplConnection.prototype.eval=function(statement){response={};try{response.value=eval(statement)}catch(err){response.error=err.message}return response};ReplConnection.prototype.initSocket=function(e){if(this.socket!==undefined&&this.socket!==null){this.socket.close()}var t="ws://"+this.host+":"+this.port+"/echo";this.socket=new WebSocket(t);e()};ReplConnection.prototype.handleSocketOpen=function(){this.active=true;console.log("REPL: socket ready")};ReplConnection.prototype.tryConnection=function(){console.log("REPL: waiting for connection");if(this.reconnect){var e=this;window.setTimeout(function(){e.start()},this.retryTime)}};ReplConnection.prototype.handleSocketClose=function(e){if(!this.active){this.tryConnection()}else{console.log("REPL: socket closed");this.active=false;if(this.reconnect){this.tryConnection()}}};ReplConnection.prototype.handleMessageReceived=function(e){if(this.debug){console.log("REPL: message received");console.log(e)}var t=JSON.parse(e.data);var n=t.timestamp;t.timestamp=new Date(n);if(this.onReceive!==undefined){this.onReceive(t)}var r=this.eval(t.statement);r.timestamp=(new Date).getTime();var i=JSON.stringify(r);if(this.debug){console.log("REPL: replying ");console.log(r)}this.socket.send(i)};ReplConnection.prototype.initEventHandling=function(){var e=this;this.socket.onopen=function(){e.handleSocketOpen()};this.socket.onclose=function(t){e.handleSocketClose(t)};this.socket.onmessage=function(t){e.handleMessageReceived(t)}};ReplConnection.prototype.start=function(e){if(this.supported){var t=this;this.initSocket(function(){t.initEventHandling();if(e!==undefined){e(t)}})}}
|
@@ -0,0 +1,117 @@
|
|
1
|
+
// A connection to the REPL server using Websocket
|
2
|
+
function ReplConnection(host, port, options) {
|
3
|
+
if (options === null) {
|
4
|
+
options = {};
|
5
|
+
}
|
6
|
+
this.debug = !!options.debug;
|
7
|
+
this.reconnect = !!options.reconnect;
|
8
|
+
this.retryTime = options.retryTime || 1000;
|
9
|
+
this.onReceive = options.onReceive;
|
10
|
+
this.host = host;
|
11
|
+
this.port = port;
|
12
|
+
this.active = false;
|
13
|
+
this.socket;
|
14
|
+
this.supported = ("WebSocket" in window);
|
15
|
+
if (this.supported) {
|
16
|
+
console.log("REPL: socket ok");
|
17
|
+
} else {
|
18
|
+
console.log("REPL: socket not supported");
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
// This is the "eval" for the REPL
|
23
|
+
ReplConnection.prototype.eval = function(statement) {
|
24
|
+
response = {}
|
25
|
+
try {
|
26
|
+
response.value = eval(statement);
|
27
|
+
} catch(err) {
|
28
|
+
response.error = err.message;
|
29
|
+
}
|
30
|
+
return response;
|
31
|
+
}
|
32
|
+
|
33
|
+
// Initialize the Websocket connection
|
34
|
+
ReplConnection.prototype.initSocket = function(successCallback) {
|
35
|
+
if (this.socket !== undefined && this.socket !== null) {
|
36
|
+
this.socket.close();
|
37
|
+
}
|
38
|
+
var address = "ws://" + this.host + ":" + this.port + "/echo";
|
39
|
+
this.socket = new WebSocket(address);
|
40
|
+
successCallback();
|
41
|
+
}
|
42
|
+
|
43
|
+
// To be run when the Websocket registers as being open
|
44
|
+
ReplConnection.prototype.handleSocketOpen = function() {
|
45
|
+
this.active = true;
|
46
|
+
console.log("REPL: socket ready");
|
47
|
+
}
|
48
|
+
|
49
|
+
// Try to create a Websocket connection
|
50
|
+
ReplConnection.prototype.tryConnection = function() {
|
51
|
+
console.log("REPL: waiting for connection");
|
52
|
+
if (this.reconnect) {
|
53
|
+
var connection = this;
|
54
|
+
window.setTimeout(function() {
|
55
|
+
connection.start();
|
56
|
+
}, this.retryTime);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
// To be run when the Websocket registers as being closed. This includes when it's waiting for a connection.
|
61
|
+
ReplConnection.prototype.handleSocketClose = function(event) {
|
62
|
+
if (!this.active) {
|
63
|
+
this.tryConnection();
|
64
|
+
} else {
|
65
|
+
console.log("REPL: socket closed");
|
66
|
+
this.active = false;
|
67
|
+
if (this.reconnect) {
|
68
|
+
this.tryConnection();
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
// To be run when the Websocket registers an event over the connection.
|
74
|
+
ReplConnection.prototype.handleMessageReceived = function(event) {
|
75
|
+
if (this.debug) {
|
76
|
+
console.log("REPL: message received");
|
77
|
+
console.log(event);
|
78
|
+
}
|
79
|
+
var message = JSON.parse(event.data);
|
80
|
+
// turn the timestamp from the rec'd message into a real date
|
81
|
+
var timestamp = message.timestamp;
|
82
|
+
message.timestamp = new Date(timestamp);
|
83
|
+
//
|
84
|
+
if (this.onReceive !== undefined) {
|
85
|
+
this.onReceive(message); // fire the custom callback
|
86
|
+
}
|
87
|
+
// prepare the response
|
88
|
+
var response = this.eval(message.statement); // evaluate the statement
|
89
|
+
response.timestamp = new Date().getTime(); // timestamp for the returned message
|
90
|
+
var json = JSON.stringify(response);
|
91
|
+
if (this.debug) {
|
92
|
+
console.log("REPL: replying ");
|
93
|
+
console.log(response);
|
94
|
+
}
|
95
|
+
this.socket.send(json);
|
96
|
+
}
|
97
|
+
|
98
|
+
// Initialize the Websocket event handling actions
|
99
|
+
ReplConnection.prototype.initEventHandling = function() {
|
100
|
+
var connection = this;
|
101
|
+
this.socket.onopen = function() { connection.handleSocketOpen() };
|
102
|
+
this.socket.onclose = function(event) { connection.handleSocketClose(event); };
|
103
|
+
this.socket.onmessage = function(event) { connection.handleMessageReceived(event); };
|
104
|
+
}
|
105
|
+
|
106
|
+
// Initialize the Websocket and start waiting for a REPL connection
|
107
|
+
ReplConnection.prototype.start = function(successCallback) {
|
108
|
+
if (this.supported) {
|
109
|
+
var connection = this;
|
110
|
+
this.initSocket(function() {
|
111
|
+
connection.initEventHandling();
|
112
|
+
if (successCallback !== undefined) {
|
113
|
+
successCallback(connection);
|
114
|
+
}
|
115
|
+
});
|
116
|
+
}
|
117
|
+
}
|
data/lib/web-repl.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# libs
|
2
|
+
require "colorize"
|
3
|
+
require "em-websocket"
|
4
|
+
require "json"
|
5
|
+
require "readline"
|
6
|
+
require "socket"
|
7
|
+
|
8
|
+
# classes
|
9
|
+
require "web-repl/messager"
|
10
|
+
require "web-repl/patch"
|
11
|
+
require "web-repl/repl"
|
12
|
+
|
13
|
+
module WebRepl
|
14
|
+
|
15
|
+
VERSION = "0.1"
|
16
|
+
|
17
|
+
# Shortcut to REPL.start
|
18
|
+
def self.start(*a)
|
19
|
+
REPL.start(*a)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module WebRepl
|
2
|
+
|
3
|
+
# Handles sending and receiving messages to/from the socket
|
4
|
+
class Messager
|
5
|
+
|
6
|
+
# @param [EventMachine::WebSocket] socket
|
7
|
+
# @param [Hash] options
|
8
|
+
# @option options [Boolean] :debug
|
9
|
+
def initialize(socket, options = {})
|
10
|
+
@socket = socket
|
11
|
+
@debug = options[:debug]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Handle an inputted message
|
15
|
+
# @param [String] raw_message A raw inputted JSON message
|
16
|
+
# @return [Hash]
|
17
|
+
def in(raw_message, &block)
|
18
|
+
hash = JSON.parse(raw_message, :symbolize_names => true)
|
19
|
+
hash[:timestamp] = Time.at(hash[:timestamp].to_i / 1000) if !hash[:timestamp].nil?
|
20
|
+
yield(hash) if block_given?
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
|
24
|
+
# Generate a new timestamp in js format
|
25
|
+
# @return [Fixnum]
|
26
|
+
def new_timestamp
|
27
|
+
Time.now.to_i * 1000 # javascript time int format
|
28
|
+
end
|
29
|
+
|
30
|
+
# Send a message over the socket
|
31
|
+
# @param [Hash] message A message to send
|
32
|
+
# @return [String, nil] If a message was sent, its JSON string; otherwise nil
|
33
|
+
def out(message)
|
34
|
+
if !@socket.nil?
|
35
|
+
message[:timestamp] ||= new_timestamp
|
36
|
+
json = message.to_json
|
37
|
+
@debug.puts "Sending message: #{json}" if @debug
|
38
|
+
@socket.send(json)
|
39
|
+
json
|
40
|
+
else
|
41
|
+
@debug.puts "Warning: No connection" if @debug
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Patch EventMachine::WebSocket so that we can initialize EM on demand. This is useful when
|
2
|
+
# having multiple EMs working. It won't error out by calling EM.run repeatedly.
|
3
|
+
#
|
4
|
+
module EventMachine
|
5
|
+
module WebSocket
|
6
|
+
def self.start(options = {}, &block)
|
7
|
+
EM.epoll
|
8
|
+
if EM.reactor_running?
|
9
|
+
handle_start(options, &block)
|
10
|
+
else
|
11
|
+
EM.run { handle_start(options, &block) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.run(options = {}, &block)
|
16
|
+
if EM.reactor_running?
|
17
|
+
handle_run(options, &block)
|
18
|
+
else
|
19
|
+
EM.run { handle_run(options, &block) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def self.handle_run(options = {}, &block)
|
26
|
+
host, port = options.values_at(:host, :port)
|
27
|
+
EM.start_server(host, port, Connection, options) do |c|
|
28
|
+
yield c
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.handle_start(options = {}, &block)
|
33
|
+
trap("TERM") { stop }
|
34
|
+
trap("INT") { stop }
|
35
|
+
run(options, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module WebRepl
|
2
|
+
|
3
|
+
# The main REPL object
|
4
|
+
class REPL
|
5
|
+
|
6
|
+
attr_reader :thread
|
7
|
+
|
8
|
+
# Start a repl connection
|
9
|
+
# @param [Hash] config A hash of config options to be passed to EM::WebSocket.run directly
|
10
|
+
# @param [Hash] options
|
11
|
+
# @option options [IO, nil] :debug A debug logger or nil if debug is not needed (default: nil)
|
12
|
+
# @option options [Boolean] :background Do not wait for input, just run in the bg
|
13
|
+
# @return [WebRepl::REPL]
|
14
|
+
def self.start(config, options = {})
|
15
|
+
new(config, options).tap { |repl| repl.start(options) }
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [Hash] config A hash of config options to be passed to EM::WebSocket.run directly
|
19
|
+
# @param [Hash] options
|
20
|
+
# @option options [IO, nil] :debug A debug logger or nil if debug is not needed (default: nil)
|
21
|
+
def initialize(config, options = {})
|
22
|
+
@config = config
|
23
|
+
@socket = nil
|
24
|
+
@messager = nil
|
25
|
+
@buffer = []
|
26
|
+
@debug = options[:debug]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Send a statement to the browser for evaluation
|
30
|
+
# @param [Fixnum, String] statement A Javascript statement to be evaluated
|
31
|
+
# @return [String, nil] The data that was sent to the browser, or nil if sending could not be completed.
|
32
|
+
def evaluate(statement)
|
33
|
+
@messager.out({ :statement => statement }) unless @messager.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Prompt the Ruby user for input and send that input to the browser for evaluation (blocking)
|
37
|
+
# @return [String, nil] The data that was sent to the browser, or nil if sending could not be completed
|
38
|
+
def gets
|
39
|
+
line = Readline.readline('> ', true)
|
40
|
+
return nil if line.nil?
|
41
|
+
if line =~ /^\s*$/ or Readline::HISTORY.to_a[-2] == line
|
42
|
+
Readline::HISTORY.pop
|
43
|
+
end
|
44
|
+
statement = line.strip
|
45
|
+
case statement
|
46
|
+
when "exit" then exit
|
47
|
+
else
|
48
|
+
evaluate(statement)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Wait for a response from the browser
|
53
|
+
def wait_for_response
|
54
|
+
loop until !@buffer.empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
# Start the Websocket connection (blocking)
|
58
|
+
# @param [Hash] options
|
59
|
+
# @option options [Boolean] :background Do not wait for input, just run in the bg
|
60
|
+
def start(options = {}, &block)
|
61
|
+
@thread = Thread.new do
|
62
|
+
EM::WebSocket.run(@config) do |ws|
|
63
|
+
if @socket.nil?
|
64
|
+
@socket = ws
|
65
|
+
@messager = Messager.new(@socket)
|
66
|
+
configure_event_handling(:background => options[:background], &block)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
acknowledge_handshake do
|
71
|
+
yield if block_given?
|
72
|
+
gets unless !!options[:background]
|
73
|
+
end
|
74
|
+
@thread.join unless !!options[:background]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Execute a block when a connection is made
|
78
|
+
# @return [TrueClass]
|
79
|
+
def acknowledge_handshake(&block)
|
80
|
+
Thread.new do
|
81
|
+
loop until !@handshake.nil?
|
82
|
+
yield
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Close the REPL
|
87
|
+
def close
|
88
|
+
@socket.close unless @socket.nil?
|
89
|
+
@thread.kill unless @thread.nil?
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def handle_open(handshake, options = {})
|
95
|
+
puts "web-repl: Connection open"
|
96
|
+
@handshake = handshake
|
97
|
+
end
|
98
|
+
|
99
|
+
def handle_close
|
100
|
+
puts "web-repl: Connection closed"
|
101
|
+
@handshake = nil
|
102
|
+
end
|
103
|
+
|
104
|
+
def handle_message_received(raw_message, options = {})
|
105
|
+
@messager.in(raw_message) do |message|
|
106
|
+
@buffer.clear
|
107
|
+
@buffer << message
|
108
|
+
keys = { :error => :red, :value => :white }
|
109
|
+
text = nil
|
110
|
+
keys.each do |k,v|
|
111
|
+
text ||= message[k].to_s.send(v) unless message[k].nil?
|
112
|
+
end
|
113
|
+
puts(text)
|
114
|
+
end
|
115
|
+
gets unless !!options[:background]
|
116
|
+
end
|
117
|
+
|
118
|
+
# Configure the Websocket event handling
|
119
|
+
# @param [Hash] options
|
120
|
+
# @option options [Boolean] :background Do not wait for input, just run in the bg
|
121
|
+
def configure_event_handling(options = {})
|
122
|
+
@socket.onopen { |handshake| handle_open(handshake) }
|
123
|
+
@socket.onclose { handle_close }
|
124
|
+
@socket.onmessage { |raw_message| handle_message_received(raw_message) }
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class WebRepl::MessagerTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include WebRepl
|
6
|
+
|
7
|
+
context "Messager" do
|
8
|
+
|
9
|
+
setup do
|
10
|
+
@socket = Object.new
|
11
|
+
@messager = Messager.new(@socket)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "#in" do
|
15
|
+
|
16
|
+
setup do
|
17
|
+
@message = { :value => "blah", :timestamp => 1396406728702 }.to_json
|
18
|
+
@result = @messager.in(@message)
|
19
|
+
end
|
20
|
+
|
21
|
+
should "convert from String to Hash" do
|
22
|
+
assert_not_nil @result
|
23
|
+
assert_equal Hash, @result.class
|
24
|
+
assert_equal "blah", @result[:value]
|
25
|
+
end
|
26
|
+
|
27
|
+
should "convert timestamp from js time to ruby" do
|
28
|
+
timestamp = @result[:timestamp]
|
29
|
+
assert_not_nil timestamp
|
30
|
+
assert_equal Time, timestamp.class
|
31
|
+
assert_equal 2014, timestamp.year
|
32
|
+
assert_equal 4, timestamp.month
|
33
|
+
assert_equal 22, timestamp.hour
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
context "#new_timestamp" do
|
39
|
+
|
40
|
+
should "be js int time format" do
|
41
|
+
result = @messager.new_timestamp
|
42
|
+
assert_not_nil result
|
43
|
+
assert_equal Fixnum, result.class
|
44
|
+
assert result.to_s.size > Time.new.to_i.to_s.size
|
45
|
+
assert_equal (result / 1000).to_s.size, Time.new.to_i.to_s.size
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
context "#out" do
|
51
|
+
|
52
|
+
setup do
|
53
|
+
@message = { :statement => "something" }
|
54
|
+
end
|
55
|
+
|
56
|
+
should "not overwrite timestamp" do
|
57
|
+
@socket.expects(:send).once
|
58
|
+
ts = Time.now.to_i / 1000
|
59
|
+
@message[:timestamp] = ts
|
60
|
+
@messager.out(@message)
|
61
|
+
assert_equal ts, @message[:timestamp]
|
62
|
+
end
|
63
|
+
|
64
|
+
should "generate new timestamp" do
|
65
|
+
@socket.expects(:send).once
|
66
|
+
@messager.out(@message)
|
67
|
+
assert_not_nil @message[:timestamp]
|
68
|
+
assert_equal Fixnum, @message[:timestamp].class
|
69
|
+
end
|
70
|
+
|
71
|
+
should "return nil if fails" do
|
72
|
+
messager = Messager.new(nil)
|
73
|
+
result = messager.out(@message)
|
74
|
+
assert_nil result
|
75
|
+
end
|
76
|
+
|
77
|
+
should "return json string if success" do
|
78
|
+
@socket.expects(:send).once
|
79
|
+
result = @messager.out(@message)
|
80
|
+
assert_not_nil result
|
81
|
+
assert_equal String, result.class
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
data/test/repl_test.rb
ADDED
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: web-repl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ari Russo
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-04-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: colorize
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: em-websocket
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: mocha
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: shoulda-context
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Javascript/Web REPL in Ruby
|
95
|
+
email:
|
96
|
+
- ari.russo@gmail.com
|
97
|
+
executables:
|
98
|
+
- web-repl
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- bin/web-repl
|
103
|
+
- js/replConnection-0.1.min.js
|
104
|
+
- js/replConnection.js
|
105
|
+
- lib/web-repl/messager.rb
|
106
|
+
- lib/web-repl/patch.rb
|
107
|
+
- lib/web-repl/repl.rb
|
108
|
+
- lib/web-repl.rb
|
109
|
+
- test/helper.rb
|
110
|
+
- test/messager_test.rb
|
111
|
+
- test/repl_test.rb
|
112
|
+
- LICENSE
|
113
|
+
- README.md
|
114
|
+
homepage: http://github.com/arirusso/web-repl
|
115
|
+
licenses: []
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
require_paths:
|
119
|
+
- lib
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.3.6
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project: web-repl
|
134
|
+
rubygems_version: 1.8.25
|
135
|
+
signing_key:
|
136
|
+
specification_version: 3
|
137
|
+
summary: Javascript/Web REPL in Ruby
|
138
|
+
test_files:
|
139
|
+
- test/messager_test.rb
|
140
|
+
- test/repl_test.rb
|