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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in railsquest.gemspec
4
+ gem 'rest-client'
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'