atcoder_tools 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21578ce616e39fd778e17427eb0a1bee8a13fe4b2161331b83601b26b389cfdb
4
- data.tar.gz: 0cb19e3f8c40624a6215ebe903ed64579ee4446655a2ef3d2eb6be384c95ac6b
3
+ metadata.gz: e5d0c7a03c8491024c16d6ae87c288f04954180fe6bd3e189db5e3d8118faebf
4
+ data.tar.gz: 4967f7572872f9e90d1a30753a6c9c2c810392a5a78ee4936580de2b2016fe02
5
5
  SHA512:
6
- metadata.gz: b0c8ce53618f75d4eb7202d8439599fe1e0eaeb6b0d0fef6c9fe0c7a8824293bcc38a7954a4c139f15f3fa81cf590e3a45e32b369ab311843a190f1a0012e7f0
7
- data.tar.gz: 06cc6d61fd01079fbc5795ff0d7f4f1f4b352b178033eb39354f7ebd8e53825c36bbef892b5015b9c3b068f413aaea5e0a41311597b04ac3f12e2fc9c8440053
6
+ metadata.gz: b36e09e331d51158b46712cfa49e585b18e1be0e72385463b49fcc4bb0cc86060ffed4968469e9be0fd9dc48d8e1f4bae559ab98e526a0938e9b343c47510282
7
+ data.tar.gz: d758c5a868d0df29e73e9be659f6499eb383301dfca75835ccdcd210e34634d7307df61e7a5ac525a5f560a119dff2ebefa18858871aab27f5ca999c8ba8ccec
data/.envrc ADDED
@@ -0,0 +1 @@
1
+ ATCODER_TOOLS_ENV=development
@@ -0,0 +1,54 @@
1
+ name: Publish Gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - v*
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - uses: actions/checkout@v2
13
+ - uses: actions/setup-ruby@v1
14
+ with:
15
+ ruby-version: '2.7'
16
+
17
+ - name: Bundle install
18
+ run: bundle
19
+
20
+ - name: Build Gem
21
+ run: rake build
22
+
23
+ - name: Publish gem
24
+ uses: dawidd6/action-publish-gem@v1
25
+ with:
26
+ api_key: ${{secrets.RUBYGEMS_API_KEY}}
27
+
28
+ # - name: mkdir gem
29
+ # run: mkdir ~/.gem
30
+
31
+ # - name: Add api key
32
+ # run: "echo :rubygems_api_key: $RUBYGEMS_API_KEY > ~/.gem/credentials"
33
+ # env:
34
+ # RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
35
+
36
+ # - name: test
37
+ # run: cat ~/.gem/credentials
38
+
39
+ # - name: test2
40
+ # run: git status
41
+
42
+ # - name: test3
43
+ # run: "echo $RUBYGEMS_API_KEY"
44
+ # env:
45
+ # RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
46
+
47
+ # - name: set git username
48
+ # run: git config user.name "Aitaro Chaya"
49
+
50
+ # - name: set git email
51
+ # run: git config user.email "aitaro.chaya@gmail.com"
52
+
53
+ # - name: Release Gem
54
+ # run: rake release
data/.gitignore CHANGED
@@ -9,3 +9,6 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ test.rb
13
+
14
+ Gemfile.lock
data/README.md CHANGED
@@ -1,47 +1,51 @@
1
1
  # AtcoderTools
2
+ Atcoderの競技環境を簡単にsetupするためのツールです。
2
3
 
3
- TODOTODOTODO
4
-
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/atcoder_tools`. To experiment with that code, run `bin/console` for an interactive prompt.
6
-
7
- TODO: Delete this and the text above, and describe your gem
8
-
9
- ## Installation
10
-
11
- Add this line to your application's Gemfile:
12
-
13
- ```ruby
14
- gem 'atcoder_tools'
4
+ ## インストール
5
+ ```bash
6
+ $ gem install atcoder_tools
15
7
  ```
16
8
 
17
- And then execute:
18
-
19
- $ bundle install
9
+ ## 使い方
10
+ ### atcoderにログイン
11
+ ```
12
+ $ atcoder_tools login
13
+ ```
20
14
 
21
- Or install it yourself as:
15
+ ### コンテスト用ファイルの作成
16
+ ```
17
+ $ atcoder_tools create abc170
18
+ ```
22
19
 
23
- $ gem install atcoder_tools
20
+ ### コンテスト用自動デバッグ
21
+ ```
22
+ $ atcoder_tools start
23
+ ```
24
24
 
25
- ## Usage
25
+ ### コンテストの提出
26
26
  ```
27
- $ atcoder_tools abc170
27
+ $ atcoder_tools submit abc170
28
28
  ```
29
29
 
30
- ## Development
30
+ ### コンテストの削除
31
+ ```
32
+ $ atcoder_tools delete abc170
33
+ ```
31
34
 
32
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
35
+ ### MODEについて
36
+ - NONE: なにもおこらない
37
+ - DEBUG: 標準入力で、testcaseが渡されたら状態で実行される。
38
+ - RUN: 単純にファイルを実行。標準入力は自分で渡す。
39
+ - TEST: rspecを用いたテスト自動実行。どれが通っていてどれが通っていないかわかる。
33
40
 
34
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
41
+ ## Development
42
+ 本リポジトリをクローンし、path指定して、gemをインストールするとデバッグできる。
35
43
 
36
44
  ## Contributing
37
-
38
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/atcoder_tools. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/atcoder_tools/blob/master/CODE_OF_CONDUCT.md).
39
-
45
+ issueやプルリク適当に投げてくれてかまいません。
40
46
 
41
47
  ## License
42
-
43
48
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
44
49
 
45
50
  ## Code of Conduct
46
-
47
51
  Everyone interacting in the AtcoderTools project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/atcoder_tools/blob/master/CODE_OF_CONDUCT.md).
@@ -31,4 +31,6 @@ Gem::Specification.new do |spec|
31
31
  spec.add_dependency "listen"
32
32
  spec.add_dependency "rspec"
33
33
  spec.add_dependency 'nokogiri'
34
+ spec.add_dependency 'mechanize'
35
+ spec.add_dependency 'tty-prompt'
34
36
  end
@@ -0,0 +1,72 @@
1
+ require_relative 'settings'
2
+ require_relative 'log'
3
+
4
+ class Atcoder
5
+ include Log
6
+
7
+ def initialize
8
+ @settings = Settings.new
9
+ @agent = Mechanize.new
10
+ @agent.user_agent_alias = 'Mac Mozilla'
11
+ end
12
+
13
+ def self.test_login(username, password)
14
+ atcoder = Atcoder.new
15
+ return atcoder.login(username=username, password=password)
16
+ end
17
+
18
+ def self.submit(task)
19
+ atcoder = Atcoder.new
20
+ atcoder.login
21
+ atcoder.submit(task)
22
+ end
23
+
24
+ # 引数はtaskクラス
25
+ def task_url(task)
26
+ "https://atcoder.jp/contests/#{task.contest.name}/tasks/#{task.contest.name}_#{task.name}"
27
+ end
28
+
29
+ # 引数はcontest, taskクラス
30
+ def submit(task)
31
+ response = nil
32
+ @agent.get(task_url(task)) do |page|
33
+ # 1つ目のフォームはログアウト用なので2つ目を使用
34
+ form = page.forms.last
35
+ form.field_with(name: 'data.LanguageId').value = "4049"
36
+ form.field_with(name: 'sourceCode').value = task.code
37
+ response = @agent.submit(form)
38
+ end
39
+
40
+ if response.code.to_i == 200
41
+ return true
42
+ end
43
+ return false
44
+ end
45
+
46
+ def login(username=nil, password=nil)
47
+
48
+ username ||= @settings.credentials.username
49
+ password ||= @settings.credentials.password
50
+
51
+ response = nil
52
+ log_debug "try login to atcoder"
53
+ @agent.get("https://atcoder.jp/login") do |page|
54
+ # 1つ目のフォームはログアウト用なので2つ目を使用
55
+ form = page.forms.last
56
+ form.field_with(name: 'username').value = username
57
+ form.field_with(name: 'password').value = password
58
+ response = @agent.submit(form)
59
+ end
60
+
61
+ # print(response.response)
62
+ res = response.body.include?("Welcome, #{username}.")
63
+ if res
64
+ log_debug "login secceed!"
65
+ else
66
+ log_warn "login falied!"
67
+ end
68
+
69
+ return res
70
+ end
71
+
72
+ end
@@ -1,50 +1,156 @@
1
-
2
1
  require "thor"
3
2
  require 'fileutils'
4
3
  require "listen"
4
+ require 'mechanize'
5
5
  require_relative 'contest'
6
6
  require_relative 'task'
7
+ require_relative 'settings'
8
+ require_relative 'atcoder'
9
+ require "tty-prompt"
10
+ require_relative 'log'
11
+
7
12
 
8
13
  module AtcoderTools
9
14
  class CLI < Thor
10
- desc 'create [contest name]', 'create contest workspace'
15
+ include Log
16
+ Prompt = TTY::Prompt.new
17
+ desc 'login', 'login to atcoder'
18
+ def login
19
+ # 認証情報を書き込むので、gitignoreを設定する
20
+ unless Dir.exist?('.atcoder')
21
+ Dir.mkdir('.atcoder')
22
+ end
23
+ File.open(".atcoder/.gitignore", mode = "w"){|f|
24
+ f.write("*") # ファイルに書き込む
25
+ }
26
+ loop do
27
+ prompt = TTY::Prompt.new
28
+ username = prompt.ask("What is your atcoder username?", required: true)
29
+ password = prompt.mask("What is your atcoder password?", required: true)
30
+ puts ""
31
+ log_info 'starting test login.'
32
+
33
+ if Atcoder.test_login(username, password)
34
+ settings = Settings.new
35
+ settings.username = username
36
+ settings.password = password
37
+ settings.save!
38
+ log_info 'OK!'
39
+ break
40
+ else
41
+ log_error "Your username or password is invalid! try again!"
42
+ end
43
+ end
44
+ end
45
+
46
+ desc 'logout', 'logout from atcoder.'
47
+ def logout
48
+ settings = Settings.new
49
+ settings.destroy_credentials!
50
+ settings.save!
51
+ end
52
+
53
+ desc 'language [lang?]', '言語を選択できます。現在対応している言語は ruby, c++(gcc) です。'
54
+ def language(lang='')
55
+ unless ['ruby', 'c++(gcc)'].include?(lang)
56
+ lang = Prompt.select("choose your default language.", ['ruby', 'c++(gcc)'])
57
+ end
58
+
59
+ # コマンドが通っているかテスト
60
+ log_info "Checking path ..."
61
+ res = case lang
62
+ when 'ruby'
63
+ !!system('ruby -v')
64
+ when 'c++(gcc)'
65
+ !!system('c++ -v')
66
+ end
67
+
68
+ unless res
69
+ raise "Cannot find path of #{lang}. Is `$ #{lang} -v` working?"
70
+ end
71
+
72
+ settings = Settings.new
73
+ settings.language = lang
74
+ settings.save!
75
+ puts
76
+ log_info 'Default language successfully changed!'
77
+ end
78
+
79
+ desc 'create [contest name]', 'create contest workspace. contest name は actoderのurlより取得できます。(ex. abc173)'
11
80
  def create(contest_name)
12
81
  contest = Contest.new(contest_name)
82
+ contest.check_validity!
13
83
  contest.create!
14
84
 
15
- puts 'successfully created'
85
+ log_info 'successfully created'
16
86
  end
17
87
 
18
88
  desc 'start', 'start run'
19
89
  def start
20
- # system('bundle exec guard -d --guardfile .atcoder/Guardfile')
21
90
  listener = Listen.to('.', ignore: /.atcoder\/.*/) do |modified, added, removed|
22
- # puts "modified absolute path: #{modified}"
23
- # puts "added absolute path: #{added}"
24
- # puts "removed absolute path: #{removed}"
25
91
  if modified[0]
26
92
  contest_name ,task_name = modified[0].split('/')[-2..-1]
27
- task_name = task_name[..-4] # .rb抜き出し
28
-
29
- puts("#{contest_name}/#{task_name}.rb was changed")
93
+ task_name = task_name.scan(/(.*)\..*/)[0][0]
30
94
 
31
95
  contest = Contest.new(contest_name)
32
96
  # thor と名前空間がかぶっているため
33
97
  task = ::Task.new(contest, task_name)
98
+ # 最後に動かしたcontest, taskを記憶
99
+ settings = Settings.new
100
+ settings.current_contest = contest
101
+ settings.current_task = task
102
+ settings.save!
103
+
34
104
  task.run
35
105
  end
36
106
  end
37
- listener.start # not blocking
107
+ log_info 'started actoder_tools session.'
108
+ listener.start
38
109
  sleep
39
110
  end
40
111
 
41
- desc 'submit [contest name]', 'submit'
42
- def submit(contest_name, task_name)
43
- puts("まだ実装してないよ!")
112
+ desc 'submit', 'ソースコードを提出します。提出する問題は対話形式で指定できます。'
113
+ def submit
114
+ prompt = TTY::Prompt.new
115
+ # contest_name = prompt.select("Choose your submit contest?", Contest.list.map(&:name))
116
+ contest_name = Prompt.select("Choose your submit contest?") do |submit|
117
+ Contest.list.each_with_index do |contest, i|
118
+ submit.choice contest.name
119
+ if Settings.new.current_contest&.name == contest.name
120
+ submit.default i + 1
121
+ end
122
+ end
123
+ end
124
+
125
+ # contestによっては6種類ない可能性がある。
126
+ task_list = ['a', 'b', 'c', 'd', 'e', 'f']
127
+ task_name = prompt.select("Choose your tesk?") do |submit|
128
+ task_list.each_with_index do |task, i|
129
+ submit.choice task
130
+ if Settings.new.current_task&.name == task
131
+ submit.default i + 1
132
+ end
133
+ end
134
+ end
135
+
136
+ contest = Contest.new(contest_name)
137
+ # thor と名前空間がかぶっているため
138
+ task = ::Task.new(contest, task_name)
139
+ Atcoder.submit(task)
44
140
  end
45
141
 
46
- desc 'delete [contest name]', 'delete'
47
- def delete(contest_name)
142
+ desc 'delete [contest_name?]', 'delete'
143
+ def delete(contest_name=nil)
144
+ unless contest_name
145
+ contest_name = Prompt.select("Choose your submit contest?") do |submit|
146
+ Contest.list.each_with_index do |contest, i|
147
+ submit.choice contest.name
148
+ if Settings.new.current_contest&.name == contest.name
149
+ submit.default i + 1
150
+ end
151
+ end
152
+ end
153
+ end
48
154
  FileUtils.rm_rf(contest_name)
49
155
  FileUtils.rm_rf(".atcoder/#{contest_name}")
50
156
  puts 'successfully deleted'
@@ -3,6 +3,7 @@ require 'fileutils'
3
3
  require 'nokogiri'
4
4
  require 'erb'
5
5
  require_relative 'task'
6
+ require_relative 'settings'
6
7
 
7
8
  class Contest
8
9
  attr_reader :name
@@ -11,14 +12,39 @@ class Contest
11
12
  @name = name
12
13
  end
13
14
 
14
- def url(task_name)
15
- "https://atcoder.jp/contests/#{@name}/tasks/#{@name}_#{task_name}"
15
+ def check_validity!
16
+ # 実在するかcheck
17
+ begin
18
+ URI.open(url)
19
+ rescue OpenURI::HTTPError
20
+ raise 'contest name が存在しません。'
21
+ end
22
+ end
23
+
24
+ def url
25
+ "https://atcoder.jp/contests/#{@name}"
26
+ end
27
+
28
+ def submission_url
29
+ "https://atcoder.jp/contests/#{@name}/submissions/me"
16
30
  end
17
31
 
18
32
  def create!
19
33
  FileUtils.mkdir_p @name
20
34
  tasks = ['a','b','c','d','e','f'].map{|task_name| Task.new(self, task_name)}
21
35
  tasks.map(&:create!)
36
+ settings = Settings.new
37
+ settings.current_contest = @name
38
+ settings.contest_language = self, settings.language
39
+ settings.save!
40
+ end
41
+
42
+ def language
43
+ Settings.new.contest_language(self)
44
+ end
45
+
46
+ def self.list
47
+ Dir.glob("./*").select{|dir| FileTest.directory?(dir)}.map{|dir| Contest.new dir[2..-1] }
22
48
  end
23
49
 
24
50
  end
@@ -0,0 +1,25 @@
1
+ require 'logger'
2
+ module Log
3
+ LoggerIns = Logger.new(STDOUT)
4
+ if ENV['ATCODER_TOOLS_ENV'] == 'development'
5
+ LoggerIns.level = Logger::DEBUG
6
+ else
7
+ LoggerIns.level = Logger::INFO
8
+ end
9
+
10
+ def log_debug(msg)
11
+ LoggerIns.debug(msg)
12
+ end
13
+
14
+ def log_info(msg)
15
+ LoggerIns.info(msg)
16
+ end
17
+
18
+ def log_warn(msg)
19
+ LoggerIns.warn(msg)
20
+ end
21
+
22
+ def log_error(msg)
23
+ LoggerIns.error(msg)
24
+ end
25
+ end
@@ -0,0 +1,100 @@
1
+ require 'yaml'
2
+ require 'base64'
3
+ require 'fileutils'
4
+
5
+ class Settings
6
+ Credentials = Struct.new(:username, :password)
7
+
8
+ def initialize
9
+ if File.exist?(".atcoder/settings.yml")
10
+ @settings = YAML.load_file(".atcoder/settings.yml")
11
+ else
12
+ @settings = {}
13
+ end
14
+ end
15
+
16
+ def current_contest
17
+ @settings['current_contest'] && Contest.new(@settings['current_contest'])
18
+ end
19
+
20
+ def ambiguous_contest(contest)
21
+ case contest
22
+ when String
23
+ Contest.new(contest)
24
+ when Contest
25
+ contest
26
+ else
27
+ raise ArgumentError, "引数は StringまたはContestです。"
28
+ end
29
+ end
30
+
31
+ def current_contest=(contest)
32
+ @settings['current_contest'] = ambiguous_contest(contest).name
33
+
34
+ end
35
+
36
+ def current_task
37
+ current_contest && @settings['current_task'] && Task.new(current_contest, @settings['current_task'])
38
+ end
39
+
40
+ def current_task=(task)
41
+ case task
42
+ when String
43
+ task_name = task
44
+ when Task
45
+ task_name = task.name
46
+ else
47
+ raise ArgumentError, "引数は StringまたはTaskです。"
48
+ end
49
+ @settings['current_task'] = task_name
50
+ end
51
+
52
+ def language
53
+ @settings['language'] || 'ruby'
54
+ end
55
+
56
+ def language=(lang)
57
+ @settings['language'] = lang
58
+ end
59
+
60
+ def contest_language(contest)
61
+ if @settings[ambiguous_contest(contest).name]
62
+ @settings[ambiguous_contest(contest).name]['language']
63
+ else
64
+ language
65
+ end
66
+ end
67
+
68
+ # contest, languageの順に代入
69
+ def contest_language=(data)
70
+ name = ambiguous_contest(data[0]).name
71
+ @settings[name] ||= {}
72
+ @settings[name]['language'] = data[1]
73
+ end
74
+
75
+ def password=(password)
76
+ @settings['password'] = Base64.strict_encode64(password)
77
+ end
78
+
79
+ def username=(username)
80
+ @settings['username'] = username
81
+ end
82
+
83
+ def destroy_credentials!
84
+ @settings.delete('username')
85
+ @settings.delete('password')
86
+ end
87
+
88
+ def credentials
89
+ unless @settings.key?('username') && @settings.key?('password')
90
+ raise "先にログインしてください!"
91
+ end
92
+ return Credentials.new(@settings['username'], Base64.decode64(@settings['password']))
93
+ end
94
+
95
+ def save!
96
+ @settings['updated_at'] = Time.now
97
+ FileUtils.mkdir_p '.atcoder'
98
+ open('.atcoder/settings.yml' , 'w') {|f| YAML.dump(@settings , f ) }
99
+ end
100
+ end
@@ -3,8 +3,10 @@ require 'rspec'
3
3
  RSpec.describe 'test' do
4
4
  <% @tests.each do |test| %>
5
5
  it "test-<%= test[:no] %>" do
6
- io = IO.popen("ruby <%= task_file_path %>", "w+")
7
- io.puts("<%= test[:input] %>")
6
+ io = IO.popen("<%= command %>", "w+")
7
+ <% test[:inputs].each do |input| %>
8
+ io.puts("<%= input %>")
9
+ <% end %>
8
10
  io.close_write
9
11
  expect(io.readlines.join).to eq("<%= test[:output] %>")
10
12
  end
@@ -0,0 +1,20 @@
1
+ // ------------------------------------------------------------
2
+ // THIS IS METADATA FOR ATCODER_TOOLS
3
+ // BE CAREFULL WHEN YOU CHANGE THE VALUE
4
+ //
5
+ // METADATA::START<% inputs.each_with_index do |input, i| %>
6
+ // test-<%=i+1%>
7
+ // input: "<%= input.gsub(/\R/, '\\n') %>"
8
+ // output: "<%= outputs[i].gsub(/\R/, '\\n') %>"<% end %>
9
+ // MODE: TEST
10
+ // METADATA::FINISH
11
+ //
12
+ // you can add your original test case
13
+ // you can select MODE from NONE, DEBUG, RUN, TEST
14
+ // problem_url: <%= url %>
15
+ // submission_url: <%= contest.submission_url %>
16
+ // -------------------------------------------------------------
17
+
18
+ // snippets
19
+ // n = gets.to_i
20
+ // arr = gets.split(' ').map(&:to_i)
@@ -11,7 +11,8 @@
11
11
  #
12
12
  # you can add your original test case
13
13
  # you can select MODE from NONE, DEBUG, RUN, TEST
14
- # problem_url: <%=url%>
14
+ # problem_url: <%= url %>
15
+ # submission_url: <%= contest.submission_url %>
15
16
  # -------------------------------------------------------------
16
17
 
17
18
  # snippets
@@ -3,102 +3,154 @@ require 'fileutils'
3
3
  require 'nokogiri'
4
4
  require 'erb'
5
5
 
6
- # module Atcoder
7
- class Task
8
- def initialize(contest, name)
9
- @contest = contest
10
- @name = name
11
- @tests = []
12
- @test_outputs = []
13
- end
6
+ class Task
7
+ attr_reader :contest, :name
8
+
9
+ # contest引数はcontestクラス
10
+ def initialize(contest, name)
11
+ @contest = contest
12
+ @name = name
13
+ @tests = []
14
+ @test_outputs = []
15
+ end
16
+
17
+ def url
18
+ "https://atcoder.jp/contests/#{@contest.name}/tasks/#{@contest.name}_#{@name}"
19
+ end
14
20
 
15
- def url
16
- "https://atcoder.jp/contests/#{@contest.name}/tasks/#{@contest.name}_#{@name}"
21
+ def task_file_path
22
+ extension = nil
23
+ case @contest.language
24
+ when 'ruby'
25
+ extension = 'rb'
26
+ when 'c++(gcc)'
27
+ extension = 'cpp'
17
28
  end
29
+ "#{@contest.name}/#{@name}.#{extension}"
30
+ end
31
+
32
+ def compile_file_path
33
+ "#{@contest.name}/#{@name}"
34
+ end
18
35
 
19
- def task_file_path
20
- "#{@contest.name}/#{@name}.rb"
36
+ def test_file_path
37
+ ".atcoder/#{@contest.name}/#{@name}/spec.rb"
38
+ end
39
+
40
+ def template_task_file_path
41
+ extension = nil
42
+ case @contest.language
43
+ when 'ruby'
44
+ extension = 'rb'
45
+ when 'c++(gcc)'
46
+ extension = 'cpp'
21
47
  end
48
+ File.dirname(__dir__)+"/atcoder_tools/sources/task.#{extension}.erb"
49
+ end
22
50
 
23
- def test_file_path
24
- ".atcoder/#{@contest.name}/#{@name}/spec.rb"
51
+ def create!
52
+ html = URI.open(url) do |f|
53
+ charset = f.charset
54
+ f.read
25
55
  end
26
56
 
27
- def create!
28
- html = URI.open(url) do |f|
29
- charset = f.charset
30
- f.read
57
+ doc = Nokogiri::HTML.parse(html, nil, 'utf8')
58
+ samples = doc.css('.lang-ja > .part > section > pre').map { |e| e.children.text }
59
+ inputs, outputs = samples.partition.with_index { |_sample, i| i.even? }
60
+
61
+ erb = ERB.new(File.read(template_task_file_path))
62
+ File.write(task_file_path, erb.result(binding))
63
+ end
64
+
65
+ def run
66
+ read_meta_data
67
+ puts("#{@contest.name}/#{@name} is running in #{@mode} MODE")
68
+ update_spec
69
+ if @mode == "DEBUG"
70
+ compile
71
+ io = IO.popen(command, "w+")
72
+ @tests[0][:inputs].each do |input|
73
+ io.puts(input)
31
74
  end
75
+ io.close_write
76
+ puts io.readlines
77
+ end
78
+ if @mode == "RUN"
79
+ compile
80
+ system("echo put your inputs")
81
+ system(command)
82
+ end
83
+ if @mode == "TEST"
84
+ compile
85
+ system("bundle exec rspec #{test_file_path}")
86
+ end
87
+ end
32
88
 
33
- doc = Nokogiri::HTML.parse(html, nil, 'utf8')
34
- samples = doc.css('.lang-ja > .part > section > pre').map { |e| e.children.text }
35
- inputs, outputs = samples.partition.with_index { |_sample, i| i.even? }
89
+ def compile
90
+ case contest.language
91
+ when 'c++(gcc)'
92
+ p 'hoge'
93
+ system("c++ #{task_file_path} -o #{@contest.name}/#{@name}")
94
+ end
95
+ end
36
96
 
37
- erb = ERB.new(File.read(File.dirname(__dir__)+"/atcoder_tools/sources/task.rb.erb"))
38
- File.write(task_file_path, erb.result(binding))
97
+ def command
98
+ case contest.language
99
+ when 'ruby'
100
+ "ruby #{task_file_path}"
101
+ when 'c++(gcc)'
102
+ "#{compile_file_path}"
39
103
  end
104
+ end
40
105
 
41
- def run
42
- read_meta_data
43
- update_spec
44
- if @mode == "DEBUG"
45
- io = IO.popen("ruby #{task_file_path}", "w+")
46
- io.puts(@tests[0][:input])
47
- io.close_write
48
- puts io.readlines
106
+ def read_meta_data
107
+ meta_flag = false
108
+ test_no = nil
109
+ tests = []
110
+ mode = nil
111
+ File.foreach(task_file_path) do |line|
112
+ line.chomp!
113
+ if line == "# METADATA::START" || line == "// METADATA::START"
114
+ meta_flag = true
115
+ next
49
116
  end
50
- if @mode == "RUN"
51
- system("echo put your inputs")
52
- system("ruby #{task_file_path}")
117
+ if line == "# METADATA::FINISH" || line == "// METADATA::FINISH"
118
+ meta_flag = false
119
+ next
53
120
  end
54
- if @mode == "TEST"
55
- system("bundle exec rspec #{test_file_path}")
121
+ unless meta_flag
122
+ next
56
123
  end
57
- end
58
-
59
- def read_meta_data
60
- meta_flag = false
61
- test_no = nil
62
- tests = []
63
- mode = nil
64
- File.foreach(task_file_path) do |line|
65
- line.chomp!
66
- if line == "# METADATA::START"
67
- meta_flag = true
68
- next
69
- end
70
- if line == "# METADATA::FINISH"
71
- meta_flag = false
72
- next
73
- end
74
- unless meta_flag
75
- next
76
- end
77
- if line =~ /\#\stest-/
78
- test_no = line.scan(/\#\stest-(\d+)/)[0][0].to_i
79
- tests.push({ no: test_no })
80
- end
81
- if line =~ /\#\sinput:/
82
- test = tests.find{|test| test[:no] == test_no}
83
- test.merge!({ input: line.scan(/\#\sinput\:\s\"(.*)\"/)[0][0] })
84
- end
85
- if line =~ /\#\soutput:/
86
- test = tests.find{|test| test[:no] == test_no}
87
- test.merge!({ output: line.scan(/\#\soutput\:\s\"(.*)\"/)[0][0] })
88
- end
89
- if line =~ /\#\sMODE:/
90
- mode = line.scan(/\#\sMODE:\s(.+)/)[0][0]
91
- end
124
+ if line =~ /(\#|\/\/)\stest-/
125
+ test_no = line.scan(/(\#|\/\/)\stest-(\d+)/)[0][1].to_i
126
+ tests.push({ no: test_no })
127
+ end
128
+ if line =~ /(\#|\/\/)\sinput:/
129
+ test = tests.find{|test| test[:no] == test_no}
130
+ input_str = line.scan(/(\#|\/\/)\sinput\:\s\"(.*)\"/)[0][1]
131
+ inputs = input_str.chomp.split('\\n')
132
+ test.merge!({ inputs: inputs })
133
+ end
134
+ if line =~ /(\#|\/\/)\soutput:/
135
+ test = tests.find{|test| test[:no] == test_no}
136
+ test.merge!({ output: line.scan(/(\#|\/\/)\soutput\:\s\"(.*)\"/)[0][1] })
137
+ end
138
+ if line =~ /(\#|\/\/)\sMODE:/
139
+ mode = line.scan(/(\#|\/\/)\sMODE:\s(.+)/)[0][1]
92
140
  end
93
- @tests = tests
94
- @mode = mode
95
141
  end
142
+ @tests = tests
143
+ @mode = mode
144
+ end
96
145
 
97
- def update_spec
98
- FileUtils.mkdir_p ".atcoder/#{@contest.name}/#{@name}"
99
- erb = ERB.new(File.read(File.dirname(__dir__)+"/atcoder_tools/sources/spec.rb.erb"))
100
- File.write(test_file_path, erb.result(binding))
101
- end
146
+ def code
147
+ File.read(task_file_path)
148
+ end
102
149
 
150
+ def update_spec
151
+ FileUtils.mkdir_p ".atcoder/#{@contest.name}/#{@name}"
152
+ erb = ERB.new(File.read(File.dirname(__dir__)+"/atcoder_tools/sources/spec.rb.erb"))
153
+ File.write(test_file_path, erb.result(binding))
103
154
  end
104
- # end
155
+
156
+ end
@@ -1,3 +1,3 @@
1
1
  module AtcoderTools
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atcoder_tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aitaro Chaya
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-20 00:00:00.000000000 Z
11
+ date: 2020-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mechanize
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: tty-prompt
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  description: Write a longer description or delete this line.
70
98
  email:
71
99
  - aitaro.chaya@gmail.com
@@ -74,12 +102,12 @@ executables:
74
102
  extensions: []
75
103
  extra_rdoc_files: []
76
104
  files:
105
+ - ".envrc"
106
+ - ".github/workflows/deploy.yml"
77
107
  - ".gitignore"
78
108
  - ".rspec"
79
- - ".travis.yml"
80
109
  - CODE_OF_CONDUCT.md
81
110
  - Gemfile
82
- - Gemfile.lock
83
111
  - LICENSE.txt
84
112
  - README.md
85
113
  - Rakefile
@@ -88,9 +116,13 @@ files:
88
116
  - bin/setup
89
117
  - exe/atcoder_tools
90
118
  - lib/atcoder_tools.rb
119
+ - lib/atcoder_tools/atcoder.rb
91
120
  - lib/atcoder_tools/cli.rb
92
121
  - lib/atcoder_tools/contest.rb
122
+ - lib/atcoder_tools/log.rb
123
+ - lib/atcoder_tools/settings.rb
93
124
  - lib/atcoder_tools/sources/spec.rb.erb
125
+ - lib/atcoder_tools/sources/task.cpp.erb
94
126
  - lib/atcoder_tools/sources/task.rb.erb
95
127
  - lib/atcoder_tools/task.rb
96
128
  - lib/atcoder_tools/version.rb
@@ -1,6 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.7.1
6
- before_install: gem install bundler -v 2.1.4
@@ -1,50 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- atcoder_tools (0.1.0)
5
- listen
6
- nokogiri
7
- rspec
8
- thor
9
-
10
- GEM
11
- remote: https://rubygems.org/
12
- specs:
13
- diff-lcs (1.3)
14
- ffi (1.13.1)
15
- listen (3.2.1)
16
- rb-fsevent (~> 0.10, >= 0.10.3)
17
- rb-inotify (~> 0.9, >= 0.9.10)
18
- mini_portile2 (2.4.0)
19
- nokogiri (1.10.9)
20
- mini_portile2 (~> 2.4.0)
21
- rake (12.3.3)
22
- rb-fsevent (0.10.4)
23
- rb-inotify (0.10.1)
24
- ffi (~> 1.0)
25
- rspec (3.9.0)
26
- rspec-core (~> 3.9.0)
27
- rspec-expectations (~> 3.9.0)
28
- rspec-mocks (~> 3.9.0)
29
- rspec-core (3.9.2)
30
- rspec-support (~> 3.9.3)
31
- rspec-expectations (3.9.2)
32
- diff-lcs (>= 1.2.0, < 2.0)
33
- rspec-support (~> 3.9.0)
34
- rspec-mocks (3.9.1)
35
- diff-lcs (>= 1.2.0, < 2.0)
36
- rspec-support (~> 3.9.0)
37
- rspec-support (3.9.3)
38
- thor (1.0.1)
39
-
40
- PLATFORMS
41
- ruby
42
-
43
- DEPENDENCIES
44
- atcoder_tools!
45
- listen (~> 3.2)
46
- rake (~> 12.0)
47
- rspec (~> 3.0)
48
-
49
- BUNDLED WITH
50
- 2.1.4