boca-golf 0.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,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'fakeweb'
4
+ gem 'rspec', require: 'spec'
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ fakeweb (1.3.0)
6
+ rspec (2.3.0)
7
+ rspec-core (~> 2.3.0)
8
+ rspec-expectations (~> 2.3.0)
9
+ rspec-mocks (~> 2.3.0)
10
+ rspec-core (2.3.1)
11
+ rspec-expectations (2.3.0)
12
+ diff-lcs (~> 1.1.2)
13
+ rspec-mocks (2.3.0)
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ fakeweb
20
+ rspec
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/boca-golf ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+
4
+ require 'boca_golf'
5
+
6
+ BocaGolf::CommandLine.new.run ARGV, $stdout, $stderr
7
+
data/boca-golf.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "boca_golf/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'boca-golf'
7
+ s.version = BocaGolf::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["David Vollbracht"]
10
+ s.email = ["david@flipstone.com"]
11
+ s.homepage = "https://github.com/flipstone/boca-golf"
12
+ s.summary = %q{A simple rspec-based engine for playing ruby golf coding problems}
13
+ s.description = %q{boca-golf with securely load and run from the filesystem or a gist url,
14
+ execute a user-specified set of rspec examples against it, and also print of the score
15
+ (# number of charaters - lower == better!). It was built for playing ruby golf at the
16
+ Boca Ruby Meetup sessions.
17
+ }
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+ end
data/lib/boca-golf.rb ADDED
@@ -0,0 +1 @@
1
+ require 'boca_golf'
@@ -0,0 +1,11 @@
1
+ class BocaGolf
2
+ class Checker
3
+ def run(gist, rspec_args, stdout, stderr)
4
+ RSpec.configure do |config|
5
+ config.include gist.safe_module
6
+ end
7
+
8
+ RSpec::Core::Runner.run rspec_args, stderr, stdout
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ class BocaGolf
2
+ class CommandLine
3
+ def run(args, stdout, stderr)
4
+ ::Rspec::Core::Runner.disable_autorun!
5
+
6
+ gist_location, *specs = *args
7
+ stdout.puts "Testing #{gist_location} against specs:"
8
+ specs.each do |spec|
9
+ stdout.puts " - #{spec}"
10
+ end
11
+ stdout.puts
12
+
13
+ result = BocaGolf.new.run args, stdout, stderr
14
+
15
+ stdout.puts "\nCode:"
16
+ stdout.puts result.gist.code
17
+ stdout.puts "\nScore:"
18
+ stdout.puts result.score
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,60 @@
1
+ class BocaGolf
2
+ class Gist
3
+ attr_reader :code
4
+
5
+ URI_REGEXP = URI.regexp(['http', 'https', 'ftp'])
6
+
7
+ def self.load_from_location(location)
8
+ if location =~ URI_REGEXP
9
+ load_from_url location
10
+ else
11
+ load_from_file location
12
+ end
13
+ end
14
+
15
+ def self.load_from_url(gist_url)
16
+ new URI.parse(gist_url + ".txt").read
17
+ end
18
+
19
+ def self.load_from_file(file)
20
+ new File.read(file)
21
+ end
22
+
23
+ def initialize(code)
24
+ @code = code
25
+ end
26
+
27
+ def safe_module
28
+ Module.new.tap do |m|
29
+ m.send :include, insecure_module
30
+ m.send :include, proxy_module(insecure_module)
31
+ end
32
+ end
33
+
34
+ protected
35
+
36
+ def insecure_module
37
+ -> do
38
+ $SAFE = 4
39
+ Module.new.tap do |m|
40
+ m.module_eval code
41
+ end
42
+ end.call
43
+ end
44
+
45
+ def proxy_module(mod)
46
+ Module.new.tap do |proxy|
47
+ mod.instance_methods.each do |method|
48
+ proxy.module_eval %{
49
+ def #{method}(*args, &block)
50
+ -> do
51
+ $SAFE = 4
52
+ super
53
+ end.call
54
+ end
55
+ }
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,7 @@
1
+ class BocaGolf
2
+ class Result < Struct.new(:gist, :passed, :score)
3
+ def passed?
4
+ passed
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class BocaGolf
2
+ class Scorer
3
+ def score(gist)
4
+ gist.code.length
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ class BocaGolf
2
+ VERSION = "0.0.1"
3
+ end
data/lib/boca_golf.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'net/http'
2
+ require 'rspec'
3
+ require 'open-uri'
4
+
5
+ require 'boca_golf/checker'
6
+ require 'boca_golf/command_line'
7
+ require 'boca_golf/gist'
8
+ require 'boca_golf/result'
9
+ require 'boca_golf/scorer'
10
+
11
+ class BocaGolf
12
+ def run(args, stdout, stderr)
13
+ gist_location, *rspec_args = args
14
+ gist = Gist.load_from_location(gist_location)
15
+ passed = Checker.new.run gist, rspec_args, stdout, stderr
16
+ score = Scorer.new.score gist
17
+
18
+ Result.new gist, passed, score
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe BocaGolf do
4
+ it "passes if all specs passed" do
5
+ run_specs_on_gist("def reverse(a) a.reverse; end").should be_passed
6
+ end
7
+
8
+ it "doesn't pass if not all specs pass" do
9
+ run_specs_on_gist("def reverse(a) a; end").should_not be_passed
10
+ end
11
+
12
+ it "scores the gist" do
13
+ run_specs_on_gist("def reverse(a) a.reverse; end")
14
+ .score.should == 29
15
+ end
16
+
17
+ def run_specs_on_gist(gist)
18
+ gist.taint
19
+ gist.untrust
20
+
21
+ FakeWeb.register_uri :get, "https://gist.github.com/746166.txt", body: gist
22
+ stdout, stderr = StringIO.new, StringIO.new
23
+ sandboxed do
24
+ BocaGolf.new.run(["https://gist.github.com/746166", "spec/infrastructure/reverse_specs/spec.rb"], stdout, stderr)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe BocaGolf::Checker do
4
+ it "returns true if all specs pass" do
5
+ run_specs_on_gist("def reverse(a) a.reverse; end").should be_true
6
+ end
7
+
8
+ it "returns false if some specs fail" do
9
+ run_specs_on_gist("def reverse(a) a; end").should be_false
10
+ end
11
+
12
+ it "doesn't make methods available everywhere" do
13
+ run_specs_on_gist "def foobar(a) a; end"
14
+ -> { foobar '1' }.should raise_error NoMethodError
15
+ end
16
+
17
+ def run_specs_on_gist(code)
18
+ stdout, stderr = StringIO.new, StringIO.new
19
+ sandboxed do
20
+ BocaGolf::Checker.new.run(BocaGolf::Gist.new(code), ["spec/infrastructure/reverse_specs/spec.rb"], stdout, stderr)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe BocaGolf::CommandLine do
4
+ it "prints the expected result" do
5
+ gist = "def reverse(a) a.reverse; end"
6
+ FakeWeb.register_uri :get, "https://gist.github.com/746166.txt", body: gist
7
+ stdout, stderr = StringIO.new, StringIO.new
8
+
9
+ sandboxed do
10
+ BocaGolf::CommandLine.new.run(["https://gist.github.com/746166", "spec/infrastructure/reverse_specs/spec.rb"], stdout, stderr)
11
+ end
12
+
13
+ stdout.string.should =~ %r|Testing https://gist.github.com/746166 against specs:
14
+ - spec/infrastructure/reverse_specs/spec.rb
15
+
16
+ \.\.\.
17
+
18
+ Finished in \d\.\d+ seconds
19
+ 3 examples, 0 failures
20
+
21
+ Code:
22
+ def reverse\(a\) a.reverse; end
23
+
24
+ Score:
25
+ 29|
26
+ end
27
+ end
data/spec/gist_spec.rb ADDED
@@ -0,0 +1,60 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe BocaGolf::Gist do
4
+ describe "safe_module" do
5
+ it "creates a module to call methods" do
6
+ o = Object.new
7
+ o.extend BocaGolf::Gist.new("def foobar(a) a*2; end").safe_module
8
+ o.foobar(3).should == 6
9
+ end
10
+
11
+ it "evals code at safe level 4" do
12
+ -> do
13
+ BocaGolf::Gist.new(%{
14
+ def reverse(a) a.reverse; end;
15
+ class ::Object; def foo() end; end
16
+ }).safe_module
17
+ end.should raise_error(SecurityError)
18
+ end
19
+
20
+ it "calls methods at safe level 4" do
21
+ o = Object.new.tap do |o|
22
+ o.extend BocaGolf::Gist.new(%{
23
+ def foo
24
+ ::Object.class_eval { def bar() end }
25
+ end
26
+ }).safe_module
27
+ end
28
+
29
+ -> { o.foo }.should raise_error(SecurityError)
30
+ end
31
+ end
32
+
33
+ describe "load_from_url" do
34
+ it "requests the .txt version of gist" do
35
+ code = "def a(); end"
36
+ FakeWeb.register_uri :get, "https://gist.github.com/746166.txt", body: code
37
+ BocaGolf::Gist.load_from_url("https://gist.github.com/746166").code.should == code
38
+ end
39
+ end
40
+
41
+ describe "load_from_file" do
42
+ it "reads the file from disk" do
43
+ File.should_receive(:read).with("/foo/bar.rb").and_return(code = "def a(); end")
44
+ BocaGolf::Gist.load_from_file("/foo/bar.rb").code.should == code
45
+ end
46
+ end
47
+
48
+ describe "load_from_location" do
49
+ it "loads from url when argument is a valid url" do
50
+ code = "def a(); end"
51
+ FakeWeb.register_uri :get, "https://gist.github.com/746166.txt", body: code
52
+ BocaGolf::Gist.load_from_location("https://gist.github.com/746166").code.should == code
53
+ end
54
+
55
+ it "loads from file when argument is not a full url" do
56
+ File.should_receive(:read).with("/foo/bar.rb").and_return(code = "def a(); end")
57
+ BocaGolf::Gist.load_from_location("/foo/bar.rb").code.should == code
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,13 @@
1
+ describe "reverse" do
2
+ it "preserves length" do
3
+ reverse("a").length.should == 1
4
+ end
5
+
6
+ it "makes the first character the last" do
7
+ reverse("abc").chars.to_a.last.should == "a"
8
+ end
9
+
10
+ it "makes the last character first" do
11
+ reverse("abc").chars.to_a.first.should == "c"
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+ require_relative 'spec_helper'
3
+
4
+ describe BocaGolf::Scorer do
5
+ describe "score" do
6
+ it "returns the length of code" do
7
+ subject.score(BocaGolf::Gist.new("abc123")).should == 6
8
+ end
9
+
10
+ it "returns the counts characters rather than bytes" do
11
+ subject.score(BocaGolf::Gist.new("abc♥")).should == 4
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,29 @@
1
+ require 'bundler/setup'
2
+ require 'fakeweb'
3
+
4
+ require 'boca_golf'
5
+
6
+ FakeWeb.allow_net_connect = false
7
+
8
+ module RSpecTestHelper
9
+ def sandboxed(&block)
10
+ begin
11
+ @orig_config = RSpec.configuration
12
+ @orig_world = RSpec.world
13
+
14
+ new_config = RSpec::Core::Configuration.new
15
+ new_world = RSpec::Core::World.new(new_config)
16
+
17
+ RSpec.instance_variable_set(:@configuration, new_config)
18
+ RSpec.instance_variable_set(:@world, new_world)
19
+ yield
20
+ ensure
21
+ RSpec.instance_variable_set(:@configuration, @orig_config)
22
+ RSpec.instance_variable_set(:@world, @orig_world)
23
+ end
24
+ end
25
+ end
26
+
27
+ RSpec.configure do |c|
28
+ c.include RSpecTestHelper
29
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: boca-golf
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - David Vollbracht
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-06 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: "boca-golf with securely load and run from the filesystem or a gist url,\n\
22
+ execute a user-specified set of rspec examples against it, and also print of the score\n\
23
+ (# number of charaters - lower == better!). It was built for playing ruby golf at the\n\
24
+ Boca Ruby Meetup sessions.\n "
25
+ email:
26
+ - david@flipstone.com
27
+ executables:
28
+ - boca-golf
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - .gitignore
35
+ - Gemfile
36
+ - Gemfile.lock
37
+ - Rakefile
38
+ - bin/boca-golf
39
+ - boca-golf.gemspec
40
+ - lib/boca-golf.rb
41
+ - lib/boca_golf.rb
42
+ - lib/boca_golf/checker.rb
43
+ - lib/boca_golf/command_line.rb
44
+ - lib/boca_golf/gist.rb
45
+ - lib/boca_golf/result.rb
46
+ - lib/boca_golf/scorer.rb
47
+ - lib/boca_golf/version.rb
48
+ - spec/boca_golf_spec.rb
49
+ - spec/checker_spec.rb
50
+ - spec/command_line_spec.rb
51
+ - spec/gist_spec.rb
52
+ - spec/infrastructure/reverse_specs/spec.rb
53
+ - spec/scorer_spec.rb
54
+ - spec/spec_helper.rb
55
+ has_rdoc: true
56
+ homepage: https://github.com/flipstone/boca-golf
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.3.7
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: A simple rspec-based engine for playing ruby golf coding problems
87
+ test_files:
88
+ - spec/boca_golf_spec.rb
89
+ - spec/checker_spec.rb
90
+ - spec/command_line_spec.rb
91
+ - spec/gist_spec.rb
92
+ - spec/infrastructure/reverse_specs/spec.rb
93
+ - spec/scorer_spec.rb
94
+ - spec/spec_helper.rb