vimgolf 0.1.0

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.
@@ -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