vimgolf 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/.rspec ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in vimgolf.gemspec
4
+ gemspec
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ vimgolf (0.0.1)
5
+ thor
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.1.2)
11
+ rspec (2.3.0)
12
+ rspec-core (~> 2.3.0)
13
+ rspec-expectations (~> 2.3.0)
14
+ rspec-mocks (~> 2.3.0)
15
+ rspec-core (2.3.1)
16
+ rspec-expectations (2.3.0)
17
+ diff-lcs (~> 1.1.2)
18
+ rspec-mocks (2.3.0)
19
+ thor (0.14.6)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ rspec
26
+ thor
27
+ vimgolf!
@@ -0,0 +1,31 @@
1
+ # [VimGolf.com](http://www.vimgolf.com) Client
2
+
3
+ Real Vim ninjas count every keystroke - do you? Head on over to vimgolf.com, pick a challenge, and show us what you've got! The rules are simple:
4
+
5
+ * Each challenge provides an input file, and an output file
6
+ * Your goal is to modify the input file such that it matches the output
7
+ * Once you install the vimgolf CLI, pick a challenge, open a prompt and put away!
8
+
9
+ When you launch a challenge from the command line, it will be downloaded from the site and a local Vim session will be launched, which will log every keystroke you make. Once you're done, simply *:wq* (write and quit) the session and we will score your input and upload it back to the site!
10
+
11
+ Let the games begin.
12
+
13
+ ## Setup & Play
14
+
15
+ <pre>
16
+ 1. $> gem install vimgolf
17
+ 2. $> vimgolf setup (go to vimgolf.com, sign in, and grab your API key)
18
+ 3. Pick a challenge on vimgolf.com
19
+ 4. $> vimgolf put [challenge ID]
20
+ </pre>
21
+
22
+ ## Todo's & Wishlist
23
+
24
+ * At the moment, scoring is done based on the simplest possible model: bytesize of your Vim script file. Instead, we'd like to assign a score based on shortcuts and key-combinations used. Ex: visual mode gets you extra x points, etc.
25
+ * Vim script parser - distinguish between different modes, keystrokes, etc.
26
+
27
+ Other patches, tips & ideas are welcome!
28
+
29
+ ## License
30
+
31
+ (MIT License) - Copyright (c) 2010 Ilya Grigorik
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'vimgolf'
7
+
8
+ begin
9
+ VimGolf::CLI.start
10
+ rescue VimGolf::Error => e
11
+ VimGolf.ui.print_exception(e)
12
+ exit(1)
13
+ rescue Interrupt => e
14
+ puts
15
+ VimGolf.ui.print_exception(e)
16
+ VimGolf.ui.say("Quitting...")
17
+ exit(1)
18
+ end
@@ -0,0 +1,9 @@
1
+ require 'fileutils'
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'thor'
5
+
6
+ require 'vimgolf/version'
7
+ require 'vimgolf/config'
8
+ require 'vimgolf/cli'
9
+ require 'vimgolf/ui'
@@ -0,0 +1,161 @@
1
+ module VimGolf
2
+
3
+ GOLFHOST = ENV['GOLFHOST'] || "http://vimgolf.com"
4
+
5
+ class Error
6
+ end
7
+
8
+ class UI
9
+ def debug(*); end
10
+ end
11
+
12
+ class << self
13
+ attr_accessor :ui
14
+
15
+ def ui
16
+ @ui ||= UI.new
17
+ end
18
+ end
19
+
20
+ class CLI < Thor
21
+ include Thor::Actions
22
+
23
+ def self.start(*)
24
+ Thor::Base.shell = VimGolf::CLI::UI
25
+ VimGolf.ui = VimGolf::CLI::UI.new
26
+ super
27
+ end
28
+
29
+ desc "setup", "configure your VimGolf credentials"
30
+ long_desc <<-DESC
31
+ To participate in the challenge please go to vimgolf.com and register an
32
+ account. Once signed in, you will get your API token, which you need to
33
+ setup the command client.
34
+
35
+ If you have the token, simply run the setup and paste in your token.
36
+ DESC
37
+
38
+ def setup
39
+ token = VimGolf.ui.ask "Please specify your VimGolf API token (register on vimgolf.com to get it):"
40
+
41
+ if token =~ /[\w\d]{1,32}/
42
+ FileUtils.mkdir_p Config.path
43
+ FileUtils.mkdir_p Config.put_path
44
+ Config.save({:key => token})
45
+
46
+ VimGolf.ui.info "Saved. Happy golfing!"
47
+ else
48
+ VimGolf.ui.error "Invalid token, please double check your token on vimgolf.com"
49
+ end
50
+ end
51
+
52
+ desc "put [ID]", "launch Vim session"
53
+ long_desc <<-DESC
54
+ Launch a VimGolf session for the specified challenge ID. To find a currently
55
+ active challenge ID, please visit vimgolf.com!
56
+ DESC
57
+
58
+ def put(id = nil)
59
+ VimGolf.ui.warn "Launching VimGolf session for challenge: #{id}"
60
+
61
+ type = download(id)
62
+
63
+ if !type.nil? && !type.empty?
64
+ # - n - no swap file, memory only editing
65
+ # - --noplugin - don't load any plugins, lets be fair!
66
+ # - +0 - always start on line 0
67
+ system("vim -n --noplugin +0 -W #{log(id)} #{input(id, type)}")
68
+
69
+ if $?.exitstatus.zero?
70
+ diff = `diff --strip-trailing-cr #{input(id, type)} #{output(id)}`
71
+
72
+ if diff.size > 0
73
+ VimGolf.ui.warn "Uh oh, looks like your entry does not match the desired output:"
74
+ VimGolf.ui.warn "#"*50
75
+ puts diff
76
+ VimGolf.ui.warn "#"*50
77
+ VimGolf.ui.warn "Please try again!"
78
+ return
79
+ end
80
+
81
+ score = File.size(log(id))
82
+ VimGolf.ui.info "Success! Your output matches. Your score: #{score}"
83
+
84
+ if VimGolf.ui.yes? "Upload result to VimGolf? (yes / no)"
85
+ VimGolf.ui.warn "Uploading to VimGolf..."
86
+
87
+ if upload(id) == :ok
88
+ VimGolf.ui.info "Uploaded entry, thanks for golfing!"
89
+ VimGolf.ui.info "View the leaderboard: #{GOLFHOST}/challenges/#{id}"
90
+ else
91
+ VimGolf.ui.error "Uh oh, upload to VimGolf failed, please check your key."
92
+ end
93
+
94
+ else
95
+ VimGolf.ui.warn "Skipping upload. Thanks for playing. Give it another shot!"
96
+ end
97
+
98
+ else
99
+ error = <<-MSG
100
+ Uh oh, Vim did not exit properly. If the problem persists, please
101
+ report the error on github.com/igrigorik/vimgolf
102
+ MSG
103
+
104
+ VimGolf.ui.error error
105
+ end
106
+ end
107
+ end
108
+
109
+ private
110
+ def download(id)
111
+ begin
112
+ url = URI.parse("#{GOLFHOST}/challenges/#{id}.json")
113
+ req = Net::HTTP::Get.new(url.path)
114
+ res = Net::HTTP.start(url.host, url.port) {|http| http.request(req)}
115
+ data = JSON.parse(res.body)
116
+
117
+ if data['client'] != Vimgolf::VERSION
118
+ VimGolf.ui.error "Client version mismatch. Installed: #{Vimgolf::VERSION}, Required: #{data['client']}."
119
+ VimGolf.ui.error "\t gem install vimgolf"
120
+ raise
121
+ end
122
+
123
+ File.open(Config.put_path + "/#{id}.#{data['in']['type']}", "w") {|f| f.puts data['in']['data']}
124
+ File.open(Config.put_path + "/#{id}.output", "w") {|f| f.puts data['out']['data']}
125
+
126
+ data['in']['type']
127
+
128
+ rescue Exception => e
129
+ VimGolf.ui.error "Uh oh, couldn't download or parse challenge, please verify your challenge id and client version."
130
+ nil
131
+ end
132
+ end
133
+
134
+ def upload(id)
135
+ begin
136
+ url = URI.parse("#{GOLFHOST}/entry.json")
137
+ http = Net::HTTP.new(url.host, url.port)
138
+ res = http.start do |conn|
139
+ key = Config.load['key']
140
+ data = "challenge_id=#{id}&entry=#{IO.read(log(id))}&apikey=#{key}"
141
+ head = {'Accept' => 'application/json'}
142
+
143
+ conn.post(url.path, data, head)
144
+ end
145
+
146
+ JSON.parse(res.body)['status'].to_sym
147
+
148
+ rescue Exception => e
149
+ VimGolf.ui.error "Uh oh, entry upload has failed, please check your key."
150
+ end
151
+ end
152
+
153
+ def input(id, type); challenge(id) + ".#{type}"; end
154
+ def output(id); challenge(id) + ".output"; end
155
+ def log(id); challenge(id) + ".log"; end
156
+
157
+ def challenge(id)
158
+ Config.put_path + "/#{id}"
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,25 @@
1
+ module VimGolf
2
+ class Config
3
+ class << self
4
+ def path
5
+ "#{ENV['HOME']}/.vimgolf"
6
+ end
7
+
8
+ def put_path
9
+ path + "/put"
10
+ end
11
+
12
+ def save(conf)
13
+ File.open(path + '/config.json', 'w') do |f|
14
+ f.puts JSON.generate(conf)
15
+ end
16
+ end
17
+
18
+ def load
19
+ File.open(path + '/config.json', 'r') do |f|
20
+ JSON.parse(f.read)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,116 @@
1
+ module VimGolf
2
+ class CLI
3
+ class UI < Thor::Base.shell
4
+
5
+ def error(name, message = nil)
6
+ begin
7
+ orig_out, $stdout = $stdout, $stderr
8
+ if message
9
+ say_status name, message, :red
10
+ elsif name
11
+ say name, :red
12
+ end
13
+ ensure
14
+ $stdout = orig_out
15
+ end
16
+ end
17
+
18
+ def warn(name, message = nil)
19
+ if message
20
+ say_status name, message, :yellow
21
+ elsif name
22
+ say name, :yellow
23
+ end
24
+ end
25
+
26
+ def info(name, message = nil)
27
+ if message
28
+ say_status name, message, :green
29
+ elsif name
30
+ say name, :green
31
+ end
32
+ end
33
+
34
+ def debug(name, message = nil)
35
+ return unless ENV["DEBUG"]
36
+
37
+ if message
38
+ message = message.inspect unless message.is_a?(String)
39
+ say_status name, message, :blue
40
+ elsif name
41
+ name = name.inspect unless name.is_a?(String)
42
+ say name, :cyan
43
+ end
44
+ end
45
+
46
+ def ask(message, password = false)
47
+ begin
48
+ require 'highline'
49
+ @hl ||= HighLine.new($stdin)
50
+ if not $stdin.tty?
51
+ @hl.ask(message)
52
+ elsif password
53
+ @hl.ask(message) {|q| q.echo = "*" }
54
+ else
55
+ @hl.ask(message) {|q| q.readline = true }
56
+ end
57
+ rescue EOFError
58
+ return ''
59
+ end
60
+ end
61
+
62
+ def print_envs(apps, default_env_name = nil, simple = false)
63
+ if simple
64
+ envs = apps.map{ |a| a.environments }
65
+ envs.flatten.map{|x| x.name}.uniq.each do |env|
66
+ puts env
67
+ end
68
+ else
69
+ apps.each do |app|
70
+ puts "#{app.name} (#{app.account.name})"
71
+ if app.environments.any?
72
+ app.environments.each do |env|
73
+ short_name = env.shorten_name_for(app)
74
+
75
+ icount = env.instances_count
76
+ iname = (icount == 1) ? "instance" : "instances"
77
+
78
+ default_text = env.name == default_env_name ? " [default]" : ""
79
+
80
+ puts " #{short_name}#{default_text} (#{icount} #{iname})"
81
+ end
82
+ else
83
+ puts " (This application is not in any environments; you can make one at #{EY.config.endpoint})"
84
+ end
85
+
86
+ puts ""
87
+ end
88
+ end
89
+ end
90
+
91
+ def print_exception(e)
92
+ if e.message.empty? || (e.message == e.class.to_s)
93
+ message = nil
94
+ else
95
+ message = e.message
96
+ end
97
+
98
+ if ENV["DEBUG"]
99
+ error(e.class, message)
100
+ e.backtrace.each{|l| say(" "*3 + l) }
101
+ else
102
+ error(message || e.class.to_s)
103
+ end
104
+ end
105
+
106
+ def print_help(table)
107
+ print_table(table, :ident => 2, :truncate => true, :colwidth => 20)
108
+ end
109
+
110
+ def set_color(string, color, bold=false)
111
+ ($stdout.tty? || ENV['THOR_SHELL']) ? super : string
112
+ end
113
+
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,3 @@
1
+ module Vimgolf
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,25 @@
1
+ require "helper"
2
+
3
+ describe VimGolf do
4
+ it "provides VimGolf errors" do
5
+ VimGolf::Error.should be
6
+ end
7
+
8
+ it "sets up VimGolf.ui" do
9
+ VimGolf.ui.should be_an(VimGolf::UI)
10
+ capture_stdout do
11
+ VimGolf::CLI.start(["help"])
12
+ end
13
+ VimGolf.ui.should be_an(VimGolf::CLI::UI)
14
+ end
15
+
16
+ it "provides a help prompt" do
17
+ out = capture_stdout do
18
+ VimGolf::CLI.start(["help"])
19
+ end
20
+
21
+ out.should include("setup")
22
+ out.should include("launch")
23
+ end
24
+
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'rspec'
5
+ require 'lib/vimgolf'
6
+
7
+ require 'stringio'
8
+
9
+ module Kernel
10
+ def capture_stdio(input = nil, &block)
11
+ org_stdin, $stdin = $stdin, StringIO.new(input) if input
12
+ org_stdout, $stdout = $stdout, StringIO.new
13
+ yield
14
+ return @out = $stdout.string
15
+ ensure
16
+ $stdout = org_stdout
17
+ $stdin = org_stdin
18
+ end
19
+ alias capture_stdout capture_stdio
20
+ end
21
+
22
+ RSpec.configure do |config|
23
+ # config.include RSpec::Helpers
24
+ # config.extend RSpec::Helpers::SemanticNames
25
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "vimgolf/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "vimgolf"
7
+ s.version = Vimgolf::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ilya Grigorik"]
10
+ s.email = ["ilya@igvita.com"]
11
+ s.homepage = "http://github.com/igrigorik/vimgolf"
12
+ s.summary = "CLI client for vimgolf.com"
13
+ s.description = s.summary
14
+
15
+ s.rubyforge_project = "vimgolf"
16
+ s.add_dependency "thor"
17
+ s.add_dependency "json"
18
+
19
+ s.add_development_dependency "rspec"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vimgolf
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Ilya Grigorik
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-28 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: thor
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: json
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ type: :development
58
+ version_requirements: *id003
59
+ description: CLI client for vimgolf.com
60
+ email:
61
+ - ilya@igvita.com
62
+ executables:
63
+ - vimgolf
64
+ extensions: []
65
+
66
+ extra_rdoc_files: []
67
+
68
+ files:
69
+ - .gitignore
70
+ - .rspec
71
+ - Gemfile
72
+ - Gemfile.lock
73
+ - README.md
74
+ - Rakefile
75
+ - bin/vimgolf
76
+ - lib/vimgolf.rb
77
+ - lib/vimgolf/cli.rb
78
+ - lib/vimgolf/config.rb
79
+ - lib/vimgolf/ui.rb
80
+ - lib/vimgolf/version.rb
81
+ - spec/cli_spec.rb
82
+ - spec/helper.rb
83
+ - vimgolf.gemspec
84
+ has_rdoc: true
85
+ homepage: http://github.com/igrigorik/vimgolf
86
+ licenses: []
87
+
88
+ post_install_message:
89
+ rdoc_options: []
90
+
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ requirements: []
110
+
111
+ rubyforge_project: vimgolf
112
+ rubygems_version: 1.3.7
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: CLI client for vimgolf.com
116
+ test_files:
117
+ - spec/cli_spec.rb
118
+ - spec/helper.rb