jtest 0.1.1 → 0.2.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.
- data/Gemfile +1 -0
- data/README.rdoc +56 -1
- data/VERSION +1 -1
- data/ext/mkrf_conf.rb +14 -0
- data/jtest.gemspec +9 -2
- data/lib/jtest/cli.rb +4 -0
- data/lib/jtest/commands/find.rb +34 -0
- data/lib/jtest/commands/new.rb +36 -30
- data/lib/jtest/commands.rb +2 -1
- data/lib/jtest/problem.rb +98 -77
- data/lib/jtest/templates/main.tt +8 -0
- metadata +24 -4
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,61 @@
|
|
1
1
|
= jtest
|
2
|
+
jtest is a command-line tool designed to improve your productivity when solving problems from http://jutge.org
|
2
3
|
|
3
|
-
|
4
|
+
jtest provides some simple commands to finding new problems and creating workspaces to solve them. Also, jtest can compile and test your "solutions" with the public samples of the problems.
|
5
|
+
|
6
|
+
== Usage
|
7
|
+
|
8
|
+
=== Finding a problem
|
9
|
+
$ jtest find Treasures
|
10
|
+
working Trying to find problems that match: Treasures
|
11
|
+
P70690 Treasures in a map (1)
|
12
|
+
P60796 Treasures in a map (2)
|
13
|
+
P90766 Treasures in a map (3)
|
14
|
+
P39846 Treasures in a map (4)
|
15
|
+
found 4 matches found!
|
16
|
+
|
17
|
+
This will show all the problems that contain `Treasures` in his name!
|
18
|
+
|
19
|
+
=== Creating a new problem
|
20
|
+
Let's create a workspace for solving `Treasures in a map (1)`.
|
21
|
+
$ jtest new 70690
|
22
|
+
connecting Getting info about problem P70690_en...
|
23
|
+
found P70690_en: Treasures in a map (1)
|
24
|
+
working Creating workspace for P70690_en: Treasures in a map (1)
|
25
|
+
create P70690_Treasures_in_a_map_(1)
|
26
|
+
create P70690_Treasures_in_a_map_(1)/sample1.dat
|
27
|
+
create P70690_Treasures_in_a_map_(1)/sample1.out
|
28
|
+
create P70690_Treasures_in_a_map_(1)/sample2.dat
|
29
|
+
create P70690_Treasures_in_a_map_(1)/sample2.out
|
30
|
+
create P70690_Treasures_in_a_map_(1)/sample3.dat
|
31
|
+
create P70690_Treasures_in_a_map_(1)/sample3.out
|
32
|
+
create P70690_Treasures_in_a_map_(1)/main.cc
|
33
|
+
As you can see, jtest automatically downloads every public sample of the problem and creates a C++ main file to start solving your problem.
|
34
|
+
|
35
|
+
=== Testing your solutions
|
36
|
+
All right! I think I've solved the problem we created before. Let's see if it passes the public samples!
|
37
|
+
$ jtest test
|
38
|
+
testing Running tests on P70690_Treasures_in_a_map_(1)...
|
39
|
+
compile P70690_Treasures_in_a_map_(1)/main.cc
|
40
|
+
running P70690_Treasures_in_a_map_(1)/sample1.dat
|
41
|
+
wrong P70690_Treasures_in_a_map_(1)/sample1.out
|
42
|
+
running P70690_Treasures_in_a_map_(1)/sample2.dat
|
43
|
+
wrong P70690_Treasures_in_a_map_(1)/sample2.out
|
44
|
+
running P70690_Treasures_in_a_map_(1)/sample3.dat
|
45
|
+
wrong P70690_Treasures_in_a_map_(1)/sample3.out
|
46
|
+
---------------------------------------------------
|
47
|
+
failed 0
|
48
|
+
missing 0
|
49
|
+
wrong 3
|
50
|
+
passed 0
|
51
|
+
total 3
|
52
|
+
---------------------------------------------------
|
53
|
+
Ooops! It seems my solution doesn't work very well... When the Nth sample test fails jtest saves the output of your solution as sampleN_test.out in the problem's workspace, so you can see what's going wrong.
|
54
|
+
|
55
|
+
=== Getting help
|
56
|
+
You can obtain help about how to use one command with the help command. For example:
|
57
|
+
$ jtest help new
|
58
|
+
Will show you all the information you need to use the `new` command (syntax, options, description, etc.).
|
4
59
|
|
5
60
|
== Contributing to jtest
|
6
61
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/ext/mkrf_conf.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
# the whole reason this file exists: to return an error if openssl
|
4
|
+
# isn't installed.
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
# create dummy rakefile to indicate success
|
8
|
+
f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w")
|
9
|
+
f.write("task :default\n")
|
10
|
+
f.close
|
11
|
+
|
12
|
+
# based on
|
13
|
+
# https://github.com/tablatom/hobo/commit/0085d4d3c5fdf2f71ca8f4412927c5147fa3d96f
|
14
|
+
# Thanks tablatom! ;)
|
data/jtest.gemspec
CHANGED
@@ -5,14 +5,15 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "jtest"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["H\u{e9}ctor Ram\u{f3}n Jim\u{e9}nez"]
|
12
|
-
s.date = "
|
12
|
+
s.date = "2013-01-16"
|
13
13
|
s.description = "Tool for automatic testing and creating problems from Jutge.org"
|
14
14
|
s.email = "hector0193@gmail.com"
|
15
15
|
s.executables = ["jtest"]
|
16
|
+
s.extensions = ["ext/mkrf_conf.rb"]
|
16
17
|
s.extra_rdoc_files = [
|
17
18
|
"LICENSE.txt",
|
18
19
|
"README.rdoc"
|
@@ -25,14 +26,17 @@ Gem::Specification.new do |s|
|
|
25
26
|
"Rakefile",
|
26
27
|
"VERSION",
|
27
28
|
"bin/jtest",
|
29
|
+
"ext/mkrf_conf.rb",
|
28
30
|
"jtest.gemspec",
|
29
31
|
"lib/jtest.rb",
|
30
32
|
"lib/jtest/cli.rb",
|
31
33
|
"lib/jtest/commands.rb",
|
34
|
+
"lib/jtest/commands/find.rb",
|
32
35
|
"lib/jtest/commands/new.rb",
|
33
36
|
"lib/jtest/commands/test.rb",
|
34
37
|
"lib/jtest/commands/update.rb",
|
35
38
|
"lib/jtest/problem.rb",
|
39
|
+
"lib/jtest/templates/main.tt",
|
36
40
|
"test/helper.rb",
|
37
41
|
"test/jtest/test_problem.rb",
|
38
42
|
"test/test_jtest.rb"
|
@@ -48,6 +52,7 @@ Gem::Specification.new do |s|
|
|
48
52
|
|
49
53
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
54
|
s.add_runtime_dependency(%q<thor>, [">= 0"])
|
55
|
+
s.add_runtime_dependency(%q<htmlentities>, ["~> 4.3.1"])
|
51
56
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
52
57
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
53
58
|
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
@@ -55,6 +60,7 @@ Gem::Specification.new do |s|
|
|
55
60
|
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
56
61
|
else
|
57
62
|
s.add_dependency(%q<thor>, [">= 0"])
|
63
|
+
s.add_dependency(%q<htmlentities>, ["~> 4.3.1"])
|
58
64
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
59
65
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
60
66
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
@@ -63,6 +69,7 @@ Gem::Specification.new do |s|
|
|
63
69
|
end
|
64
70
|
else
|
65
71
|
s.add_dependency(%q<thor>, [">= 0"])
|
72
|
+
s.add_dependency(%q<htmlentities>, ["~> 4.3.1"])
|
66
73
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
67
74
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
68
75
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
data/lib/jtest/cli.rb
CHANGED
@@ -8,6 +8,10 @@ module Jtest
|
|
8
8
|
|
9
9
|
add_runtime_options!
|
10
10
|
|
11
|
+
register Jtest::Commands::Find, "find", "find [NAME]",
|
12
|
+
"Finds all the problems that match with the given name"
|
13
|
+
tasks["find"].options = Jtest::Commands::Find.class_options
|
14
|
+
|
11
15
|
register Jtest::Commands::New, "new", "new [ID]",
|
12
16
|
"Creates a workspace to solve problem with the given id"
|
13
17
|
tasks["new"].options = Jtest::Commands::New.class_options
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "htmlentities"
|
2
|
+
require "jtest/problem"
|
3
|
+
|
4
|
+
module Jtest
|
5
|
+
module Commands
|
6
|
+
class Find < Thor::Group
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
desc "Finds all the problems that match with the given name"
|
10
|
+
|
11
|
+
argument :name, :type => :string, :desc => "A problem name to match"
|
12
|
+
|
13
|
+
def get_problems
|
14
|
+
say_status :working, "Trying to find problems that match: #{name}", :yellow
|
15
|
+
@problems = Problem.find(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def show_problems
|
19
|
+
coder = HTMLEntities.new
|
20
|
+
@problems.each do |problem|
|
21
|
+
say_status problem[0], coder.decode(problem[1]), :blue
|
22
|
+
end
|
23
|
+
|
24
|
+
if @problems.empty?
|
25
|
+
say_status :not_found, "0 matches found :(", :red
|
26
|
+
else
|
27
|
+
say_status :found,
|
28
|
+
"#{@problems.size} match#{'es' if @problems.size != 1} found!",
|
29
|
+
:green
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/jtest/commands/new.rb
CHANGED
@@ -1,39 +1,45 @@
|
|
1
1
|
require "jtest/problem"
|
2
2
|
|
3
3
|
module Jtest
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
4
|
+
module Commands
|
5
|
+
class New < Thor::Group
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
desc "Creates a workspace to solve problem with the given id"
|
9
|
+
|
10
|
+
argument :id, :type => :numeric, :desc => "The problem identifier"
|
11
|
+
class_option :lang, :type => :string, :aliases => '-l', :desc => "Language of the problem",
|
12
|
+
:default => 'en'
|
13
|
+
class_option :prefix, :type => :string, :aliases => '-p', :desc => "Prefix of the problem",
|
14
|
+
:default => 'P'
|
15
|
+
|
16
|
+
def self.source_root
|
17
|
+
File.dirname(__FILE__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_problem_info
|
21
|
+
@problem = Problem.new(id, options)
|
22
|
+
|
23
|
+
say_status :connecting, "Getting info about problem #{@problem.id}...", :yellow
|
24
|
+
@problem.retrieve_info
|
25
|
+
|
26
|
+
raise "Problem #{@problem.id} not found :(" unless @problem.exists?
|
27
|
+
|
28
|
+
say_status :found, @problem.title, :green
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_workspace
|
32
|
+
say_status :working, "Creating workspace for #{@problem.title}", :yellow
|
33
|
+
|
34
|
+
empty_directory @problem.dirname
|
31
35
|
|
32
36
|
@problem.samples.each_with_index do |sample, index|
|
33
37
|
create_file "#{@problem.dirname}/sample#{index+1}.dat", sample[0]
|
34
38
|
create_file "#{@problem.dirname}/sample#{index+1}.out", sample[1]
|
35
39
|
end
|
40
|
+
|
41
|
+
template "../templates/main.tt", "#{@problem.dirname}/main.cc"
|
36
42
|
end
|
37
|
-
|
38
|
-
|
39
|
-
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/jtest/commands.rb
CHANGED
data/lib/jtest/problem.rb
CHANGED
@@ -2,80 +2,101 @@ require "open-uri"
|
|
2
2
|
require "openssl"
|
3
3
|
|
4
4
|
module Jtest
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
5
|
+
class Problem
|
6
|
+
URL = "https://www.jutge.org/problems/"
|
7
|
+
REGEXPS = {
|
8
|
+
:title => /<title>Jutge :: Problem (.+?)<\/title>/,
|
9
|
+
:samples => /<pre.+?>(.+?)<\/pre>/m,
|
10
|
+
:dir_id => /[0-9]+/,
|
11
|
+
:invalid_url => "Wrong URL."
|
12
|
+
}
|
13
|
+
DEFAULT_OPTIONS = {:lang => 'en', :prefix => 'P', :dirname => nil}
|
14
|
+
|
15
|
+
attr_reader :id
|
16
|
+
attr_reader :title
|
17
|
+
attr_reader :samples
|
18
|
+
attr_reader :dirname
|
19
|
+
|
20
|
+
def initialize(id, options = {})
|
21
|
+
options = DEFAULT_OPTIONS.merge(options)
|
22
|
+
|
23
|
+
@id = options[:prefix] + id.to_s + '_' + options[:lang]
|
24
|
+
@title = nil
|
25
|
+
@samples = []
|
26
|
+
@dirname = options[:dirname]
|
27
|
+
end
|
28
|
+
|
29
|
+
def connect
|
30
|
+
url = URL + @id
|
31
|
+
@source = open(url, :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE).read
|
32
|
+
end
|
33
|
+
|
34
|
+
def exists?
|
35
|
+
connect if @source.nil?
|
36
|
+
|
37
|
+
not @source.include? REGEXPS[:invalid_url]
|
38
|
+
end
|
39
|
+
|
40
|
+
def retrieve_info
|
41
|
+
connect
|
42
|
+
|
43
|
+
return false unless exists?
|
44
|
+
|
45
|
+
@title = @source.scan(REGEXPS[:title])[0][0]
|
46
|
+
@samples = @source.scan(REGEXPS[:samples]).flatten.each_slice(2).to_a
|
47
|
+
@dirname = @title.gsub(/_(.+?)\:/, '').gsub(/\s/, '_') if @dirname.nil?
|
48
|
+
|
49
|
+
return true
|
50
|
+
end
|
51
|
+
|
52
|
+
class << self
|
53
|
+
def select(ids, options = {})
|
54
|
+
options = DEFAULT_OPTIONS.merge(options)
|
55
|
+
dirs = dirs_match(ids)
|
56
|
+
|
57
|
+
problems = []
|
58
|
+
dirs.each do |dir|
|
59
|
+
REGEXPS[:dir_id].match(dir) do |match|
|
60
|
+
options[:dirname] = dir
|
61
|
+
problems << Problem.new(match, options) unless match.nil?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
return problems
|
66
|
+
end
|
67
|
+
|
68
|
+
def find(name)
|
69
|
+
list_entry = /
|
70
|
+
<td.+?> # Before problem id
|
71
|
+
(P[0-9]+) # Capture problem id
|
72
|
+
<\/.+?td> # After problem id
|
73
|
+
\n # Line break
|
74
|
+
\s+? # Possible whitespaces
|
75
|
+
<td.+?> # Before problem title
|
76
|
+
( # Capture problem title
|
77
|
+
[^<>]*? # All characters except HTML tags
|
78
|
+
#{Regexp.quote(name)} # Match the given name
|
79
|
+
[^<>]*? # Same as before
|
80
|
+
) # End capture
|
81
|
+
<\/.+?td>/x # After problem title
|
82
|
+
|
83
|
+
source = open(URL, :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE).read
|
84
|
+
problems = source.scan(list_entry).flatten.each_slice(2).to_a
|
85
|
+
|
86
|
+
return problems
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
def dirs_match(ids)
|
91
|
+
if ids == ["all"]
|
92
|
+
dirs = Dir["[PX]*_*"]
|
93
|
+
else
|
94
|
+
dirs = []
|
95
|
+
ids.each { |id| dirs += Dir["#{id}*"] }
|
96
|
+
end
|
97
|
+
|
98
|
+
return dirs
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jtest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: htmlentities
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 4.3.1
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 4.3.1
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: shoulda
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,7 +127,8 @@ description: Tool for automatic testing and creating problems from Jutge.org
|
|
111
127
|
email: hector0193@gmail.com
|
112
128
|
executables:
|
113
129
|
- jtest
|
114
|
-
extensions:
|
130
|
+
extensions:
|
131
|
+
- ext/mkrf_conf.rb
|
115
132
|
extra_rdoc_files:
|
116
133
|
- LICENSE.txt
|
117
134
|
- README.rdoc
|
@@ -123,14 +140,17 @@ files:
|
|
123
140
|
- Rakefile
|
124
141
|
- VERSION
|
125
142
|
- bin/jtest
|
143
|
+
- ext/mkrf_conf.rb
|
126
144
|
- jtest.gemspec
|
127
145
|
- lib/jtest.rb
|
128
146
|
- lib/jtest/cli.rb
|
129
147
|
- lib/jtest/commands.rb
|
148
|
+
- lib/jtest/commands/find.rb
|
130
149
|
- lib/jtest/commands/new.rb
|
131
150
|
- lib/jtest/commands/test.rb
|
132
151
|
- lib/jtest/commands/update.rb
|
133
152
|
- lib/jtest/problem.rb
|
153
|
+
- lib/jtest/templates/main.tt
|
134
154
|
- test/helper.rb
|
135
155
|
- test/jtest/test_problem.rb
|
136
156
|
- test/test_jtest.rb
|
@@ -149,7 +169,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
149
169
|
version: '0'
|
150
170
|
segments:
|
151
171
|
- 0
|
152
|
-
hash:
|
172
|
+
hash: -358689626784226077
|
153
173
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
174
|
none: false
|
155
175
|
requirements:
|