railsquest 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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +26 -0
- data/Readme.md +134 -0
- data/bin/railsquest +61 -0
- data/development.log +1 -0
- data/lib/railsquest.rb +119 -0
- data/lib/railsquest/badge.rb +84 -0
- data/lib/railsquest/bonjour.rb +9 -0
- data/lib/railsquest/bonjour/advertiser.rb +66 -0
- data/lib/railsquest/bonjour/browser.rb +58 -0
- data/lib/railsquest/bonjour/person.rb +25 -0
- data/lib/railsquest/bonjour/quest.rb +39 -0
- data/lib/railsquest/bonjour/quest_browser.rb +36 -0
- data/lib/railsquest/bonjour/railsquest_browser.rb +32 -0
- data/lib/railsquest/commands.rb +53 -0
- data/lib/railsquest/grit_extensions.rb +11 -0
- data/lib/railsquest/helpers.rb +100 -0
- data/lib/railsquest/quest.rb +86 -0
- data/lib/railsquest/version.rb +3 -0
- data/railsquest.gemspec +21 -0
- data/sinatra/app.rb +162 -0
- data/sinatra/config.ru +2 -0
- data/sinatra/lib/diff_helpers.rb +92 -0
- data/sinatra/lib/mock_browsers.rb +55 -0
- data/sinatra/public/jquery-1.3.2.min.js +19 -0
- data/sinatra/public/loader.gif +0 -0
- data/sinatra/public/logo.png +0 -0
- data/sinatra/public/pbjt.swf +0 -0
- data/sinatra/public/peanut.png +0 -0
- data/sinatra/public/rm.gif +0 -0
- data/sinatra/public/theme.mp3 +0 -0
- data/sinatra/views/home.haml +32 -0
- data/sinatra/views/layout.haml +346 -0
- data/sinatra/views/readme.haml +52 -0
- data/sinatra/views/run.haml +1 -0
- data/sinatra/views/user.haml +21 -0
- metadata +103 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
lib = File.expand_path('../lib/', __FILE__)
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
3
|
+
|
4
|
+
desc "Boot up railsquest"
|
5
|
+
task :default do
|
6
|
+
exec "bundle exec bin/railsquest"
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Boot up just the web interface"
|
10
|
+
task :web do
|
11
|
+
exec "bundle exec thin start -c #{File.dirname(__FILE__)}/sinatra -p 4567"
|
12
|
+
end
|
13
|
+
|
14
|
+
require "railsquest/version"
|
15
|
+
version = Railsquest::VERSION
|
16
|
+
gem_name = "railsquest-#{version}.gem"
|
17
|
+
|
18
|
+
desc "Build #{gem_name}"
|
19
|
+
task :build do
|
20
|
+
system "gem build railsquest.gemspec"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Tag and push #{gem_name}"
|
24
|
+
task :push => :build do
|
25
|
+
system "git tag #{version} && git push && git push --tags && gem push #{gem_name}"
|
26
|
+
end
|
data/Readme.md
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
Railsquest - Propose and pursue quests for Ruby programming glory!
|
2
|
+
==================================================================
|
3
|
+
|
4
|
+
Pursue fame and glory by discovering and completing Quests, or offer a Quest to challenge your friends!
|
5
|
+
As you complete Quests, your trophy page will slowly fill up with your achievement badges.
|
6
|
+
|
7
|
+
Railsquest brings the magic of Bonjour auto-discovery to find Quests and other Challengers in your network.
|
8
|
+
|
9
|
+
Installation and usage
|
10
|
+
----------------------
|
11
|
+
|
12
|
+
Install it (from [gemcutter](http://gemcutter.org/)) via gems:
|
13
|
+
|
14
|
+
gem install railsquest
|
15
|
+
|
16
|
+
(you might need to do a `gem sources -a http://gemcutter.org` beforehand!)
|
17
|
+
|
18
|
+
Start it up:
|
19
|
+
|
20
|
+
railsquest
|
21
|
+
|
22
|
+
Then fire up [http://localhost:9876/](http://localhost:9876/) to begin your quest for the holy (g)rails!
|
23
|
+
|
24
|
+
Your name, as it will be seen by other people, is taken from your git global config setting.
|
25
|
+
|
26
|
+
You will see a list of all current adventurers, and a list of all available quests.
|
27
|
+
You can inspect the badges that have been won by other adventurers, and visit the quests to try them yourself.
|
28
|
+
|
29
|
+
How to create a quest
|
30
|
+
---------------------
|
31
|
+
|
32
|
+
Your quest is a web application running on your machine.
|
33
|
+
You can run it on any port you choose.
|
34
|
+
To make the quest available to other adventurers, add it to your railsquests:
|
35
|
+
|
36
|
+
railsquest add <port> "Name of your quest"
|
37
|
+
|
38
|
+
Specify the correct port number, and the name of your quest.
|
39
|
+
|
40
|
+
An adventurer will commence your quest by browsing from their Railsquest page.
|
41
|
+
Your quest application will receive a GET request with a "host" parameter.
|
42
|
+
The host is the computer hostname of the challenger (again from the git global config).
|
43
|
+
(TODO: We also need to make the adventurer's personal name available)
|
44
|
+
|
45
|
+
When you decide that an adventurer has completed your quest, you must notify
|
46
|
+
your local Railsquest server of their success by posting two parameters to
|
47
|
+
|
48
|
+
http://localhost:9876/submit
|
49
|
+
|
50
|
+
The post must contain these two parameters:
|
51
|
+
|
52
|
+
* The adventurer's "hostname"
|
53
|
+
* The "quest_name"
|
54
|
+
|
55
|
+
For example:
|
56
|
+
|
57
|
+
require 'rest-client'
|
58
|
+
|
59
|
+
RestClient.post 'http://localhost:9876/submit', :hostname => hostname, :quest_name => 'My Funky Quest'
|
60
|
+
|
61
|
+
Or using JQuery:
|
62
|
+
|
63
|
+
$.post('http://localhost:9876/submit', {hostname: hostname, quest_name: 'My Funky Quest'});
|
64
|
+
|
65
|
+
Railsquest will then sign these facts into an achievement badge that will be displayed on the adventurer's trophy page!
|
66
|
+
|
67
|
+
Linux support
|
68
|
+
-------------
|
69
|
+
|
70
|
+
To install the dnssd gem on Linux you'll need [avahi](http://avahi.org/). For Ubunutu peeps this means:
|
71
|
+
|
72
|
+
sudo aptitude update
|
73
|
+
|
74
|
+
sudo aptitude install g++ ruby-dev \
|
75
|
+
libavahi-compat-libdnssd-dev avahi-discover avahi-utils
|
76
|
+
|
77
|
+
and you'll need to set the domain-name:
|
78
|
+
|
79
|
+
sudo sed -i \
|
80
|
+
-e 's/#domain-name=local/domain-name=local/' \
|
81
|
+
/etc/avahi/avahi-daemon.conf
|
82
|
+
|
83
|
+
sudo service avahi-daemon restart
|
84
|
+
|
85
|
+
You can debug whether or not Avahi can see Railsquest and git-daemon Bonjour statuses using the command 'avahi-browse'. This command can be found in the package 'avahi-utils'.
|
86
|
+
|
87
|
+
The following command will show you all of the Bonjour services running on your local network:
|
88
|
+
|
89
|
+
avahi-browse --all
|
90
|
+
|
91
|
+
If you kill railsquest with kill -9 it doesn't get a chance to unregister the Bonjour services, and when it is restarted it will die with DNSSD::AlreadyRegisteredError. Although not ideal, you can work around this my restarting avahi-daemon first.
|
92
|
+
|
93
|
+
Note: You might have to restart the avahi-daemon sometimes if you are having problems seeing other railsquests.
|
94
|
+
|
95
|
+
Developing
|
96
|
+
----------
|
97
|
+
|
98
|
+
bundle install
|
99
|
+
rake -T
|
100
|
+
|
101
|
+
Contributors
|
102
|
+
------------
|
103
|
+
|
104
|
+
* [Sam Dalton](http://github.com/samdalton/)
|
105
|
+
* [Michael Dowse](http://michaeldowse.name/)
|
106
|
+
* [Clifford Heath](http://dataconstellation.com/)
|
107
|
+
* [Eaden McKee](@eadz)
|
108
|
+
* [Cameron Walsh]
|
109
|
+
|
110
|
+
With blithe cribbage from bananajour by...
|
111
|
+
* [Tim Lucas](http://www.toolmantim.com)
|
112
|
+
* [Carla Hackett](http://carlahackettdesign.com/) (logo)
|
113
|
+
* [Nathan de Vries](http://github.com/atnan)
|
114
|
+
* [Lachlan Hardy](http://github.com/lachlanhardy)
|
115
|
+
* [Josh Bassett](http://github.com/nullobject)
|
116
|
+
* [Myles Byrne](http://github.com/quackingduck)
|
117
|
+
* [Ben Hoskings](http://github.com/benhoskings)
|
118
|
+
* [Brett Goulder](http://github.com/brettgo1)
|
119
|
+
* [Tony Issakov](https://github.com/tissak)
|
120
|
+
* [Mark Bennett](http://github.com/MarkBennett)
|
121
|
+
* [Travis Swicegood](http://github.com/tswicegood)
|
122
|
+
* [Nate Haas](http://github.com/natehaas)
|
123
|
+
* [James Sadler](http://github.com/freshtonic)
|
124
|
+
* [Jason King](http://github.com/JasonKing)
|
125
|
+
* [Michael Pope](http://github.com/map7)
|
126
|
+
|
127
|
+
License
|
128
|
+
-------
|
129
|
+
|
130
|
+
All directories and files are MIT Licensed.
|
131
|
+
|
132
|
+
Warning to all those who still believe secrecy will save their revenue stream
|
133
|
+
-----------------------------------------------------------------------------
|
134
|
+
Bananas were meant to be shared. There are no secret bananas.
|
data/bin/railsquest
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path('../../lib/', __FILE__)
|
4
|
+
$:.unshift lib unless $:.include?(lib)
|
5
|
+
|
6
|
+
require 'railsquest'
|
7
|
+
|
8
|
+
Thread.abort_on_exception = true
|
9
|
+
|
10
|
+
Railsquest.setup! if !Railsquest.setup?
|
11
|
+
|
12
|
+
parent_process_pid = Process.pid
|
13
|
+
pids = []
|
14
|
+
at_exit do
|
15
|
+
if Process.pid == parent_process_pid
|
16
|
+
pids.each do |pid|
|
17
|
+
Process.kill("TERM", pid) rescue nil
|
18
|
+
sleep 0.2
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
case ARGV.first
|
24
|
+
|
25
|
+
when nil
|
26
|
+
pids << Railsquest.serve_web!
|
27
|
+
pids << Railsquest.advertise!
|
28
|
+
Process.waitall
|
29
|
+
|
30
|
+
when "add", "init"
|
31
|
+
quest = Railsquest.add!(ARGV[1], ARGV[2])
|
32
|
+
|
33
|
+
when "remove", "rm"
|
34
|
+
name = ARGV[1]
|
35
|
+
|
36
|
+
if !name || name.empty?
|
37
|
+
abort "You need to specify the name of the quest you'd like to remove:\n#{File.basename($0)} remove <path>"
|
38
|
+
elsif !(quest = Railsquest::Quest.for_name(name))
|
39
|
+
abort "#{name.inspect} is not a valid quest name"
|
40
|
+
end
|
41
|
+
|
42
|
+
quest.remove!
|
43
|
+
|
44
|
+
when "help", "--help", "-h"
|
45
|
+
puts <<-HELP
|
46
|
+
Usage: #{File.basename($0)} [<command>]
|
47
|
+
|
48
|
+
Commands:
|
49
|
+
none - Start the web, quest, and bonjour serving
|
50
|
+
add <port> <name> - Add a quest running on server port with given name
|
51
|
+
remove <name> - Remove a quest
|
52
|
+
help
|
53
|
+
version
|
54
|
+
HELP
|
55
|
+
|
56
|
+
when "version", "--version", "-v"
|
57
|
+
puts "railsquest version #{Railsquest::VERSION}"
|
58
|
+
|
59
|
+
else
|
60
|
+
abort "Say what? Try: #{File.basename($0)} help"
|
61
|
+
end
|
data/development.log
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Logfile created on 2011-03-19 00:36:04 +1300 by logger.rb/25413
|
data/lib/railsquest.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
libdir = File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
3
|
+
|
4
|
+
require 'railsquest/quest'
|
5
|
+
require 'railsquest/badge'
|
6
|
+
require 'railsquest/grit_extensions'
|
7
|
+
require 'railsquest/version'
|
8
|
+
require 'railsquest/bonjour'
|
9
|
+
require 'railsquest/helpers'
|
10
|
+
require 'railsquest/commands'
|
11
|
+
|
12
|
+
require 'ostruct'
|
13
|
+
require 'socket'
|
14
|
+
require 'pathname'
|
15
|
+
require 'rest-client'
|
16
|
+
|
17
|
+
module Railsquest
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
include DateHelpers
|
22
|
+
include GravatarHelpers
|
23
|
+
include Commands
|
24
|
+
|
25
|
+
def setup?
|
26
|
+
quests_path.exist?
|
27
|
+
badges_path.exist?
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup!
|
31
|
+
quests_path.mkpath
|
32
|
+
badges_path.mkpath
|
33
|
+
end
|
34
|
+
|
35
|
+
def path
|
36
|
+
Pathname("~/.railsquest").expand_path
|
37
|
+
end
|
38
|
+
|
39
|
+
def quests_path
|
40
|
+
path + "quests"
|
41
|
+
end
|
42
|
+
|
43
|
+
def badges_path
|
44
|
+
path + "badges"
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_git_global_config(key)
|
48
|
+
`git config --global #{key}`.strip
|
49
|
+
end
|
50
|
+
|
51
|
+
def config
|
52
|
+
@config ||= begin
|
53
|
+
OpenStruct.new({
|
54
|
+
:name => get_git_global_config("user.name"),
|
55
|
+
:email => get_git_global_config("user.email")
|
56
|
+
})
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def web_port
|
61
|
+
9876
|
62
|
+
end
|
63
|
+
|
64
|
+
def web_uri
|
65
|
+
"http://#{host_name}:#{web_port}/"
|
66
|
+
end
|
67
|
+
|
68
|
+
def host_name
|
69
|
+
hn = get_git_global_config("railsquest.hostname")
|
70
|
+
unless hn.nil? or hn.empty?
|
71
|
+
return hn
|
72
|
+
end
|
73
|
+
|
74
|
+
hn = Socket.gethostname
|
75
|
+
|
76
|
+
# if there is more than one period in the hostname then assume it's a FQDN
|
77
|
+
# and the user knows what they're doing
|
78
|
+
return hn if hn.count('.') > 1
|
79
|
+
|
80
|
+
if hn =~ /\.local$/
|
81
|
+
hn
|
82
|
+
else
|
83
|
+
hn + ".local"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def quest_uri
|
88
|
+
"http://#{host_name}/"
|
89
|
+
end
|
90
|
+
|
91
|
+
def quests
|
92
|
+
quests_path.children.reject{ |b| b.to_s =~ /DS_Store/}.map {|q| Quest.new(q) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def quest(name)
|
96
|
+
quests.find {|r| r.name == name}
|
97
|
+
end
|
98
|
+
|
99
|
+
def badges
|
100
|
+
badges_path.children.reject{ |b| b.to_s =~ /DS_Store/}.map {|b| Badge.new(b).to_hash }
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_hash
|
104
|
+
{
|
105
|
+
"name" => config.name,
|
106
|
+
"email" => config.email,
|
107
|
+
"uri" => web_uri,
|
108
|
+
"git-uri" => quest_uri,
|
109
|
+
"gravatar" => Railsquest.gravatar,
|
110
|
+
"version" => Railsquest::VERSION,
|
111
|
+
"quests" => quests.collect do |r|
|
112
|
+
{"name" => r.name, "uri" => r.uri}
|
113
|
+
end
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Railsquest
|
4
|
+
class Badge
|
5
|
+
|
6
|
+
attr_accessor :name
|
7
|
+
|
8
|
+
def self.for_name(name)
|
9
|
+
n = name.gsub(' ', '_')
|
10
|
+
q = new(Railsquest.badges_path.join(n + ".badge"))
|
11
|
+
q.name = n
|
12
|
+
q
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.html_id(name)
|
16
|
+
name.gsub(/[^A-Za-z-]+/, '').downcase
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(path)
|
20
|
+
@path = Pathname(path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
other.respond_to?(:path) && self.path == other.path
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :path
|
28
|
+
|
29
|
+
def exist?
|
30
|
+
path.exist?
|
31
|
+
end
|
32
|
+
|
33
|
+
def init!(signature, original_host)
|
34
|
+
contents = '{\"signature\" : \"' + signature + '\", \"original_host\" : \"' + original_host + '\"}'
|
35
|
+
Dir.chdir(Railsquest.badges_path) { `echo #{contents} >> #{path}` }
|
36
|
+
end
|
37
|
+
|
38
|
+
def uri
|
39
|
+
Railsquest.quest_uri.gsub(/\/$/, '') + ':' + File.open(path) { |f| f.gets }
|
40
|
+
end
|
41
|
+
|
42
|
+
def name
|
43
|
+
dirname.sub(".badge",'')
|
44
|
+
end
|
45
|
+
|
46
|
+
def html_id
|
47
|
+
self.class.html_id(name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def dirname
|
51
|
+
path.split.last.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
name
|
56
|
+
end
|
57
|
+
|
58
|
+
def web_uri
|
59
|
+
Railsquest.web_uri + "#" + html_id
|
60
|
+
end
|
61
|
+
|
62
|
+
def remove!
|
63
|
+
path.rmtree
|
64
|
+
end
|
65
|
+
|
66
|
+
def verified?
|
67
|
+
contents = JSON.parse(File.read(path))
|
68
|
+
begin
|
69
|
+
RestClient.post 'http://' + contents['original_host'] + ':' + Railsquest.web_port.to_s + '/verify', { :signature => contents['signature'], :quest_name => name, :hostname => Railsquest.host_name }
|
70
|
+
rescue
|
71
|
+
false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_hash
|
76
|
+
contents = JSON.parse(File.read(path))
|
77
|
+
{
|
78
|
+
"original_host" => contents['original_host'],
|
79
|
+
"signature" => contents['signature'],
|
80
|
+
"name" => name
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Railsquest::Bonjour
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'railsquest/bonjour/person'
|
5
|
+
require 'railsquest/bonjour/quest'
|
6
|
+
require 'railsquest/bonjour/browser'
|
7
|
+
require 'railsquest/bonjour/quest_browser'
|
8
|
+
require 'railsquest/bonjour/railsquest_browser'
|
9
|
+
require 'railsquest/bonjour/advertiser'
|