coderetreat 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/bin/cr +15 -0
- data/lib/coderetreat.rb +159 -0
- metadata +47 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ODVjZmI1ZjY0ZjBkMmNkNmMyMTA2ZGY3ZGVkOWQzNjRhZGRiMDI0Yw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MjgwNjBmZjc3NTNhZWNkMDkxMmM3MDI2NTg5ZTA1ZjY3YmY1NzhhMQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OWIyMzRlOGNlMmY5MTQwOWMxOGQ3NGJhZjU3Nzk5MjBmMDdjNWM2NmJhOTE2
|
10
|
+
YzFiNjU0Y2VmMzRmNWE5Y2FhODk0ZjY1NzcwMjQ2N2ZjOWVjM2I3MGQ3OWFj
|
11
|
+
ZWRkNmNlMTgzMWZmYjg5ODE2OTdiNDYyMjAwNDMyZDA2NzgxYWI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MjYxODMyYWE4YmRmOWE5ODljMTgzZWM5YzgyN2YyMjNkMDgxNGViNTUwMWZl
|
14
|
+
YTAzODkyOWVlZTkzN2U4MDMzMjA5MDFhZTIyMjk3ZjM1ZmZmOTVmYzU2Zjc1
|
15
|
+
NGI4MjQyNDgyOWM5MjI4ZTc4MDQ4MzA3OTJjNGIzMThjMjhmN2Y=
|
data/bin/cr
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
if ARGV.length > 0
|
3
|
+
file = ARGV[0]
|
4
|
+
|
5
|
+
else
|
6
|
+
STDOUT.puts 'You need to tell me what to watch!'
|
7
|
+
STDOUT.puts 'Usage:'
|
8
|
+
STDOUT.puts 'bin/cr somefile.rb'
|
9
|
+
Kernel.exit(true)
|
10
|
+
end
|
11
|
+
|
12
|
+
configFile = 'http://jsoxford.com/cr.json'
|
13
|
+
require_relative('../lib/coderetreat.rb')
|
14
|
+
config = ARGV.length >= 3 ? {host: ARGV[1], port: ARGV[2]} : CodeRetreatRunner.config(configFile)
|
15
|
+
CodeRetreatRunner.new.run(file, config)
|
data/lib/coderetreat.rb
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'socket'
|
3
|
+
require 'json'
|
4
|
+
require 'digest'
|
5
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
6
|
+
require 'net/http'
|
7
|
+
require 'rspec'
|
8
|
+
|
9
|
+
class CodeRetreatRunner
|
10
|
+
|
11
|
+
def self.config(url)
|
12
|
+
JSON.parse(Net::HTTP.get(URI(url)))['endpoint'].with_indifferent_access
|
13
|
+
end
|
14
|
+
|
15
|
+
# Runs the runner
|
16
|
+
def run(filename, config)
|
17
|
+
STDOUT.puts "Watching #{filename}"
|
18
|
+
|
19
|
+
unless File.exists?(filename)
|
20
|
+
return STDOUT.puts 'Something went pretty badly wrong. Does that file exist?'
|
21
|
+
end
|
22
|
+
|
23
|
+
STDOUT.puts "Connecting to #{config[:host]}:#{config[:port]}"
|
24
|
+
connect(config)
|
25
|
+
|
26
|
+
# Receive data and check the test file indefinitely
|
27
|
+
loop do
|
28
|
+
test(filename) if changed(filename)
|
29
|
+
receive
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Runs the tests in the test file
|
34
|
+
def test(filename)
|
35
|
+
begin
|
36
|
+
RSpec.reset
|
37
|
+
config = RSpec.configuration
|
38
|
+
config.color = true
|
39
|
+
|
40
|
+
json_formatter = RSpec::Core::Formatters::JsonFormatter.new(config.output_stream)
|
41
|
+
reporter = RSpec::Core::Reporter.new(config)
|
42
|
+
reporter.register_listener(json_formatter, :message, :dump_summary, :stop)
|
43
|
+
config.instance_variable_set(:@reporter, reporter)
|
44
|
+
|
45
|
+
RSpec::Core::Runner.run([filename])
|
46
|
+
data = json_formatter.output_hash
|
47
|
+
|
48
|
+
setInterrupt
|
49
|
+
|
50
|
+
symbols = {passed: '✓', pending: '.', failed: '✖'}
|
51
|
+
STDOUT.puts data[:examples].map{ |example| ' ' + symbols[example[:status].to_sym] }.join('')
|
52
|
+
|
53
|
+
data[:examples].select{ |example| example[:status] == 'failed' }.map do |example|
|
54
|
+
STDOUT.puts "fail: #{example[:full_description]} -- error: #{example[:exception][:message]}"
|
55
|
+
end
|
56
|
+
|
57
|
+
send({
|
58
|
+
action: 'consumeTestResults',
|
59
|
+
payload: {
|
60
|
+
testsRun: data[:summary][:example_count],
|
61
|
+
testsFailed: data[:summary][:failure_count],
|
62
|
+
testsIgnored: data[:summary][:pending_count]
|
63
|
+
}
|
64
|
+
})
|
65
|
+
|
66
|
+
rescue Exception => e
|
67
|
+
STDOUT.puts "Failed to load your code, do you have errors in your Ruby? Exception: [#{e}]"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Connects the TCP socket
|
72
|
+
def connect(config)
|
73
|
+
@client = TCPSocket.open config[:host], config[:port]
|
74
|
+
setInterrupt
|
75
|
+
end
|
76
|
+
|
77
|
+
# Disconnects the TCP socket
|
78
|
+
def disconnect
|
79
|
+
@client.close if @client
|
80
|
+
end
|
81
|
+
|
82
|
+
# Disable rspec interrupt, and disconnect our socket on close
|
83
|
+
def setInterrupt
|
84
|
+
Signal.trap('INT') do
|
85
|
+
disconnect
|
86
|
+
Kernel.exit(0)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Sends JSON through the TCP socket
|
91
|
+
def send(data)
|
92
|
+
@client.write JSON.generate(data)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Checks if the test file has changed (no more than once a second)
|
96
|
+
def changed(filename)
|
97
|
+
changed = false
|
98
|
+
now = Time.now.to_f
|
99
|
+
|
100
|
+
@timestamp ||= now
|
101
|
+
@fileHash ||= ''
|
102
|
+
|
103
|
+
if now - @timestamp > 1
|
104
|
+
File.open(filename, "r") do |file|
|
105
|
+
fileHash = Digest::SHA1.hexdigest(File.read(filename))
|
106
|
+
changed = fileHash != @fileHash
|
107
|
+
@fileHash = fileHash
|
108
|
+
end
|
109
|
+
|
110
|
+
@timestamp = now
|
111
|
+
end
|
112
|
+
|
113
|
+
changed
|
114
|
+
end
|
115
|
+
|
116
|
+
# Responds to a request
|
117
|
+
def respond(data)
|
118
|
+
payload = data[:payload]
|
119
|
+
success = false
|
120
|
+
message = nil
|
121
|
+
|
122
|
+
begin
|
123
|
+
case data[:action]
|
124
|
+
when 'tickBoard'
|
125
|
+
# CodeRetreat.tickBoard(payload[:result])
|
126
|
+
payload = {}
|
127
|
+
success = false
|
128
|
+
when 'tickCell'
|
129
|
+
payload[:generation]++
|
130
|
+
payload[:lives] = CodeRetreat.tickCell(payload[:result])
|
131
|
+
payload[:from] = payload[:result]
|
132
|
+
payload.delete(:result)
|
133
|
+
success = true
|
134
|
+
else
|
135
|
+
message = "I don't understand the action requested: #{data[:action]}"
|
136
|
+
end
|
137
|
+
rescue Exception => e
|
138
|
+
message = "Requested action had an error: #{data[:action]}"
|
139
|
+
end
|
140
|
+
|
141
|
+
send({ respondingTo: data[:action], success: success, message: message, payload: payload })
|
142
|
+
end
|
143
|
+
|
144
|
+
# Recieve data from the TCP socket and buffers into JSON objects
|
145
|
+
def receive
|
146
|
+
@buffer ||= ''
|
147
|
+
data = @client.recv(128)
|
148
|
+
unless data.nil?
|
149
|
+
@buffer += data
|
150
|
+
|
151
|
+
jsons = @buffer.split("\n")
|
152
|
+
jsons.each do |json|
|
153
|
+
respond(JSON.parse(json).with_indifferent_access) rescue nil
|
154
|
+
end
|
155
|
+
|
156
|
+
@buffer = jsons.last unless @buffer.match(/\n$/)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: coderetreat
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pete West
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-06 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Automatically run your tests, and connect to the Code Retreat Game of
|
14
|
+
Life server to be part of the bigger picture
|
15
|
+
email: peterjwest3@gmail.com
|
16
|
+
executables:
|
17
|
+
- cr
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- bin/cr
|
22
|
+
- lib/coderetreat.rb
|
23
|
+
homepage: https://github.com/jsoxford/code-retreat-rb
|
24
|
+
licenses:
|
25
|
+
- MIT
|
26
|
+
metadata: {}
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubyforge_project:
|
43
|
+
rubygems_version: 2.2.2
|
44
|
+
signing_key:
|
45
|
+
specification_version: 4
|
46
|
+
summary: Code Retreat Game of Life runner
|
47
|
+
test_files: []
|