├── .gitignore ├── .rspec ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── atcoder_greedy.gemspec ├── bin ├── console └── setup ├── exe └── atcoder_greedy ├── lib ├── atcoder_greedy.rb └── atcoder_greedy │ ├── command.rb │ ├── command │ ├── config.rb │ ├── create.rb │ ├── destroy.rb │ ├── submit.rb │ ├── template.rb │ └── test.rb │ ├── lib │ ├── atcoder.rb │ ├── contest.rb │ ├── greedy_template.rb │ ├── languages.rb │ └── test_case.rb │ ├── settings.yml │ ├── templates │ ├── c │ │ └── solve.c │ ├── cpp │ │ └── solve.cpp │ ├── hs │ │ └── solve.hs │ ├── py │ │ └── solve.py │ └── rb │ │ └── solve.rb │ └── version.rb └── spec ├── commands └── create_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | 11 | # Created by .ignore support plugin (hsz.mobi) 12 | ### Ruby template 13 | *.gem 14 | *.rbc 15 | /.config 16 | /InstalledFiles 17 | /spec/examples.txt 18 | /test/tmp/ 19 | /test/version_tmp/ 20 | 21 | ## Specific to RubyMotion: 22 | .dat* 23 | .repl_history 24 | build/ 25 | 26 | ## Documentation cache and generated files: 27 | /.yardoc/ 28 | /rdoc/ 29 | 30 | ## Environment normalisation: 31 | /vendor/bundle 32 | /lib/bundler/man/ 33 | 34 | # for a library or gem, you might want to ignore these files since the code is 35 | # intended to run in multiple environments; otherwise, check them in: 36 | # Gemfile.lock 37 | # .ruby-version 38 | # .ruby-gemset 39 | 40 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 41 | .rvmrc 42 | 43 | ## Directory-based project format: 44 | .idea/ 45 | # if you remove the above rule, at least ignore the following: 46 | 47 | # User-specific stuff: 48 | # .idea/workspace.xml 49 | # .idea/tasks.xml 50 | # .idea/dictionaries 51 | 52 | # Sensitive or high-churn files: 53 | # .idea/dataSources.ids 54 | # .idea/dataSources.xml 55 | # .idea/sqlDataSources.xml 56 | # .idea/dynamic.xml 57 | # .idea/uiDesigner.xml 58 | 59 | # Gradle: 60 | # .idea/gradle.xml 61 | # .idea/libraries 62 | 63 | # Mongo Explorer plugin: 64 | # .idea/mongoSettings.xml 65 | 66 | ## File-based project format: 67 | *.ipr 68 | *.iws 69 | 70 | ## Plugin-specific files: 71 | 72 | # IntelliJ 73 | /out/ 74 | 75 | # mpeltonen/sbt-idea plugin 76 | .idea_modules/ 77 | 78 | # JIRA plugin 79 | atlassian-ide-plugin.xml 80 | 81 | # Crashlytics plugin (for Android Studio and IntelliJ) 82 | com_crashlytics_export_strings.xml 83 | crashlytics.properties 84 | crashlytics-build.properties 85 | 86 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.2.0 4 | before_install: gem install bundler -v 1.11.2 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all people who 5 | contribute through reporting issues, posting feature requests, updating 6 | documentation, submitting pull requests or patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free 9 | experience for everyone, regardless of level of experience, gender, gender 10 | identity and expression, sexual orientation, disability, personal appearance, 11 | body size, race, ethnicity, age, religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | * The use of sexualized language or imagery 16 | * Personal attacks 17 | * Trolling or insulting/derogatory comments 18 | * Public or private harassment 19 | * Publishing other's private information, such as physical or electronic 20 | addresses, without explicit permission 21 | * Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or 24 | reject comments, commits, code, wiki edits, issues, and other contributions 25 | that are not aligned to this Code of Conduct, or to ban temporarily or 26 | permanently any contributor for other behaviors that they deem inappropriate, 27 | threatening, offensive, or harmful. 28 | 29 | By adopting this Code of Conduct, project maintainers commit themselves to 30 | fairly and consistently applying these principles to every aspect of managing 31 | this project. Project maintainers who do not follow or enforce the Code of 32 | Conduct may be permanently removed from the project team. 33 | 34 | This code of conduct applies both within project spaces and in public spaces 35 | when an individual is representing the project or its community. 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 38 | reported by contacting a project maintainer at goog@brookbach.com. All 39 | complaints will be reviewed and investigated and will result in a response that 40 | is deemed necessary and appropriate to the circumstances. Maintainers are 41 | obligated to maintain confidentiality with regard to the reporter of an 42 | incident. 43 | 44 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 45 | version 1.3.0, available at 46 | [http://contributor-covenant.org/version/1/3/0/][version] 47 | 48 | [homepage]: http://contributor-covenant.org 49 | [version]: http://contributor-covenant.org/version/1/3/0/ -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in atcoder_greedy.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 keigo-brook 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AtcoderGreedy 2 | 楽にatcoderを使いたい. Atcoderで行われるコンテストにおいて, 自動でテンプレートやインプットを生成するGemです. 3 | 何かありましたらtwitter: @brook_bachまでお願いします. 4 | 5 | ## 実装した機能 6 | - コンテストフォルダ, 問題ファイルの生成 7 | - サンプルインプット、アウトプットを用いたテストファイルの生成, テスト実行 8 | - ユーザーテンプレート機能 9 | - 提出機能 10 | - ruby, c/c++ に対応 11 | 12 | ## Installation 13 | 14 | $ gem install atcoder_greedy 15 | 16 | ## 初期設定 17 | 18 | configコマンドを使用してデフォルト言語の設定をしてください。 19 | ``` 20 | $ atcoder_greedy config 21 | Choose default language from: ["rb", "cpp", "c"] 22 | Input languages: cpp 23 | Update Your default language to [cpp]. 24 | $ 25 | ``` 26 | 27 | ## Usage 28 | 29 | ### Createコマンド 30 | コンテスト用のフォルダ, ファイルを作成します. 31 | ``` 32 | $ atcoder_greedy create CONTEST_URL OPTION 33 | ``` 34 | 作成時に使用できるオプション 35 | 36 | | option name ARGUMENT | alias | detail | 37 | | ------------------------------------ | ----- | ------- | 38 | | --no-templates | --nt | テンプレートファイルを生成しません. | 39 | | --no-input | --ni | 入力ファイルを生成しません. | 40 | | --select-problem PROBLEM_NAMES | -p | 指定した問題のみ生成します. 複数の問題を指定する場合は'A B' のように''で囲ってください. | 41 | | --select-directory DIR_PATH | -d | 指定したディレクトリに生成します. | 42 | | --select-language LANGUAGE | -l | 指定した言語でテンプレートを生成します. | 43 | | --select-template TEMP_NAME | -t | 指定したテンプレートで生成します. | 44 | 45 | ### testコマンド 46 | テストを実行します. 入力ファイルが生成されている必要があります. 47 | ``` 48 | $ cd CONTESTNAME 49 | $ atcoder_greedy test PROBLEM_FILE_NAME 50 | ``` 51 | 52 | ### templateコマンド 53 | テンプレートの設定を行います. テンプレートは複数保存でき, 言語毎に一つデフォルトテンプレートを設定することができます. 54 | デフォルトに設定されたテンプレートは, createコマンドで作成するときに使用されます. 55 | ``` 56 | $ atcoder_greedy template OPTION 57 | ``` 58 | 使用できるオプション 59 | 60 | | option name | alias | detail | 61 | | ------------------------| ----- | ------- | 62 | | --add FILE_PATH | -a | FILE_PATHで指定されたファイルをテンプレートに追加します. | 63 | | --list | -l | テンプレート一覧を表示します. | 64 | | --set-default FILE_NAME | -s | FILE_NAMEで指定されたテンプレートをその言語のデフォルトに設定します. | 65 | | --delete FILE_NAME | -d | FILE_NAMEで指定されたテンプレートを削除します. | 66 | 67 | ### submitコマンド 68 | 問題の提出を行います. コンテストディレクトリ内で実行してください.提出が成功した場合, 結果画面をブラウザで開きます. 69 | ``` 70 | $ atcoder_greedy submit [SUBMIT_FILE] 71 | ``` 72 | 73 | ## 使用例 74 | ### 例1 75 | ARC014の場合 76 | 77 | ``` 78 | $ atcoder_greedy create http://arc014.contest.atcoder.jp 79 | ``` 80 | 81 | とすると、以下のようなファイルが生成される。 82 | 83 | ``` 84 | . 85 | ├── .contest_info.yml 86 | ├── A.rb 87 | ├── B.rb 88 | ├── C.rb 89 | ├── D.rb 90 | ├── input_A.txt 91 | ├── input_B.txt 92 | ├── input_C.txt 93 | └── input_D.txt 94 | ``` 95 | 96 | 各問題について,X.rbに自分の解答を記述すれば良い。 97 | input_X.txtにはX.rbのサンプルインプット,アウトプットが記載されている. 98 | 99 | A問題についてテストを実行するには、 100 | 101 | ``` 102 | $ atcoder_greedy test A.rb 103 | ``` 104 | 105 | とすると、以下のようにテスト結果が表示される。 106 | 107 | ``` 108 | Running a test for problem A.rb... 109 | -------------------- Compile Done -------------------- 110 | -------------------- Testcase #0 -------------------- FAILED! Time: 0.00727s 111 | Your Output: 112 | 5 113 | Correct Answer: 114 | 1 115 | 116 | -------------------- Testcase #1 -------------------- PASSED! Time: 0.04882s 117 | 118 | -------------------- Testcase #2 -------------------- FAILED! Time: 0.00614s 119 | Your Output: 120 | 3 121 | Correct Answer: 122 | 1 123 | 124 | Test done. 125 | ``` 126 | 127 | A問題を提出したい場合は, 128 | ``` 129 | $ atcoder_greedy submit A.rb 130 | Submit [A.rb] ... Done! 131 | ``` 132 | 133 | ### 例2 134 | ARC015にて, カレントディレクトリにA問題のインプットファイルのみ生成したい場合 135 | 136 | ``` 137 | $ atcoder_greedy create http://arc015.contest.atcoder.jp --nt -p A -d ./ 138 | ``` 139 | 140 | ## TODO,実装したい機能 141 | 142 | - 言語対応の拡大 143 | - gemのテスト作成 144 | 145 | ## Development 146 | 147 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 148 | 149 | 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). 150 | 151 | ## Contributing 152 | 153 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/atcoder_greedy. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 154 | ## License 155 | 156 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 157 | 158 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << "test" 6 | t.libs << "lib" 7 | t.test_files = FileList['test/**/*_test.rb'] 8 | end 9 | 10 | task :default => :spec 11 | -------------------------------------------------------------------------------- /atcoder_greedy.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'atcoder_greedy/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "atcoder_greedy" 8 | spec.version = AtcoderGreedy::VERSION 9 | spec.authors = ["keigo-brook"] 10 | spec.email = ["goog@brookbach.com"] 11 | 12 | spec.summary = %q{This gem is very useful atcoder plugin.} 13 | spec.description = %q{By using this plugin, You can create atcoder-contest templates.} 14 | spec.homepage = "https://github.com/keigo-brook/atcoder_greedy" 15 | spec.license = "MIT" 16 | 17 | # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or 18 | # delete this section to allow pushing this gem to any host. 19 | if spec.respond_to?(:metadata) 20 | spec.metadata['allowed_push_host'] = "https://rubygems.org" 21 | else 22 | raise "RubyGems 2.0 or newer is required to protect against public gem pushes." 23 | end 24 | 25 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 26 | spec.bindir = "exe" 27 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 28 | spec.require_paths = ["lib"] 29 | 30 | spec.add_development_dependency "bundler", "~> 1.11" 31 | spec.add_development_dependency "rake", "~> 10.0" 32 | spec.add_development_dependency "rspec" 33 | 34 | spec.add_dependency 'nokogiri' 35 | spec.add_dependency 'thor' 36 | spec.add_dependency 'mechanize' 37 | spec.add_dependency 'launchy' 38 | end 39 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "atcoder_greedy" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /exe/atcoder_greedy: -------------------------------------------------------------------------------- 1 | require 'atcoder_greedy' 2 | AtcoderGreedy::Command.start -------------------------------------------------------------------------------- /lib/atcoder_greedy.rb: -------------------------------------------------------------------------------- 1 | require 'open-uri' 2 | require 'nokogiri' 3 | require 'fileutils' 4 | require 'yaml' 5 | require 'mechanize' 6 | require 'launchy' 7 | 8 | require "atcoder_greedy/version" 9 | require 'atcoder_greedy/command' 10 | 11 | module AtcoderGreedy 12 | # Configuration defaults 13 | @config = { 14 | user_id: '', 15 | password: '', 16 | language: '', 17 | default_template: { 18 | rb: '', 19 | cpp: '', 20 | c: '', 21 | py: '', 22 | hs: '' 23 | } 24 | } 25 | 26 | @valid_languages = %w(rb cpp c py hs) 27 | @valid_config_keys = @config.keys 28 | 29 | # Configure through hash 30 | def self.configure(opts = {}) 31 | self.config 32 | opts.each do |k, v| 33 | if v.is_a?(Hash) 34 | v.each do |ck, cv| 35 | @config[k.to_sym][ck.to_sym] = cv if @valid_languages.include?(ck.to_s) 36 | end 37 | else 38 | @config[k.to_sym] = v if @valid_config_keys.include? k.to_sym 39 | end 40 | end 41 | self.save_config 42 | end 43 | 44 | def self.get_config_path 45 | config_path = Dir.home + '/.atcoder_greedy' 46 | if Dir.exists?(config_path) 47 | config_path 48 | else 49 | raise "Can't find config directory. please init by command: 'atcoder_greedy config'.'" 50 | end 51 | end 52 | 53 | def self.config 54 | yml_path = get_config_path + '/settings.yml' 55 | yml_file = YAML.load_file(yml_path) 56 | if yml_file 57 | @config = yml_file 58 | else 59 | File.open(yml_path, 'w') { |f| YAML.dump(@config, f) } 60 | end 61 | end 62 | 63 | def self.save_config 64 | yml_path = get_config_path + '/settings.yml' 65 | if File.exists?(yml_path) 66 | File.open(yml_path, 'w') { |f| YAML.dump(@config, f) } 67 | else 68 | raise "Can't find #{yml_path}. please set configure." 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/command.rb: -------------------------------------------------------------------------------- 1 | require 'thor' 2 | require 'atcoder_greedy' 3 | require 'atcoder_greedy/command/create' 4 | require 'atcoder_greedy/command/destroy' 5 | require 'atcoder_greedy/command/test' 6 | require 'atcoder_greedy/command/config' 7 | require 'atcoder_greedy/command/template' 8 | require 'atcoder_greedy/command/submit' 9 | 10 | module AtcoderGreedy 11 | class Command < Thor 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/command/config.rb: -------------------------------------------------------------------------------- 1 | require 'atcoder_greedy' 2 | require 'atcoder_greedy/command' 3 | require 'atcoder_greedy/lib/languages' 4 | 5 | module AtcoderGreedy 6 | class Command < Thor 7 | desc 'config', 'change settings' 8 | 9 | def config 10 | languages = Languages::ALL_LANGUAGES 11 | config_path = Dir.home + '/.atcoder_greedy' 12 | if Dir.exists?(config_path) 13 | puts "Your current user_id is #{AtcoderGreedy.config[:user_id]} and current language is [#{AtcoderGreedy.config[:language]}]." 14 | else 15 | Dir.mkdir(config_path) 16 | yml_path = AtcoderGreedy.get_config_path + '/settings.yml' 17 | File.open(yml_path, 'w').close 18 | end 19 | 20 | # user setting 21 | agent = Mechanize.new 22 | loop do 23 | print 'Input your user_id: ' 24 | user_id = $stdin.gets.chomp! 25 | print 'Input your password: ' 26 | password = $stdin.gets.chomp! 27 | break if user_id.size == 0 || password.size == 0 28 | 29 | print 'Doing test login ...' 30 | response = nil 31 | agent.get('http://abc032.contest.atcoder.jp/login') do |page| 32 | response = page.form_with(action: '/login') do |f| 33 | f.field_with(name: 'name').value = user_id 34 | f.field_with(name: 'password').value = password 35 | end.submit 36 | end 37 | 38 | if response.response['x-imojudge-simpleauth'] == 'Passed' 39 | puts 'OK!' 40 | AtcoderGreedy.configure(user_id: user_id) 41 | AtcoderGreedy.configure(password: password) 42 | break 43 | else 44 | puts 'Failed! Confirm input and try again.' 45 | end 46 | end 47 | 48 | # language setting 49 | puts "Choose default language from: #{languages}" 50 | print "Input languages: " 51 | loop do 52 | s = $stdin.gets.chomp! 53 | if languages.include?(s) 54 | AtcoderGreedy.configure(language: s) 55 | puts "Update Your default language to [#{AtcoderGreedy.config[:language]}]." 56 | break 57 | elsif s.size == 0 58 | break 59 | else 60 | puts "Invalid language. please try again:" 61 | end 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/command/create.rb: -------------------------------------------------------------------------------- 1 | require 'atcoder_greedy' 2 | require 'atcoder_greedy/command' 3 | require 'atcoder_greedy/lib/contest' 4 | 5 | module AtcoderGreedy 6 | class Command < Thor 7 | desc 'create [CONTESTURL] [OPTION]', 'create contest templates for [CONTESTURL]' 8 | option :no_templates, type: :boolean, default: false, aliases: "\--nt" 9 | option :no_input, type: :boolean, default: false, aliases: "\--ni" 10 | option :select_problem, aliases: '-p', default: nil, desc: 'create only select problem' 11 | option :select_directory, aliases: '-d', default: '', desc: 'select target directory' 12 | option :select_language, aliases: '-l', default: '', desc: 'select language' 13 | option :select_template, aliases: '-t', default: '', desc: 'select generate template' 14 | map 'c' => 'create' 15 | 16 | def create(contest_url) 17 | user_options = { 18 | no: {input: false, template: false}, 19 | problems: [], 20 | directory: options[:select_directory], 21 | language: options[:select_language], 22 | template: options[:select_template] 23 | } 24 | 25 | user_options[:no][:input] = true if options[:no_input] 26 | user_options[:no][:template] = true if options[:no_templates] 27 | user_options[:problems] = options[:select_problem].split unless options[:select_problem].nil? 28 | 29 | contest = Contest.new(contest_url, user_options) 30 | # TODO: contest_infoが存在したときの処理 31 | info = { 32 | name: contest.name, 33 | date: contest.date, 34 | url: contest.url, 35 | task: {} 36 | } 37 | contest.problems.each do |p| 38 | info[:task][:"#{p[:name]}"] = { 39 | id: p[:task_id] 40 | } 41 | end 42 | File.open("#{contest.dir}/.contest_info.yml", 'w') do |f| 43 | f.puts info.to_yaml 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/command/destroy.rb: -------------------------------------------------------------------------------- 1 | require 'atcoder_greedy' 2 | require 'atcoder_greedy/command' 3 | 4 | module AtcoderGreedy 5 | class Command < Thor 6 | desc 'destroy [CONTESTNAME]', 'destroy contest templates for [CONTESTNAME]' 7 | 8 | def destroy(contest_name) 9 | puts "Destroy ./#{contest_name} [y/n]?" 10 | s = $stdin.gets 11 | if s == 'y' || s == 'yes' 12 | if system("rm -r ./#{contest_name}") 13 | puts 'deleted.' 14 | else 15 | raise 'Runtime Error' 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/command/submit.rb: -------------------------------------------------------------------------------- 1 | require 'atcoder_greedy' 2 | require 'atcoder_greedy/command' 3 | require 'atcoder_greedy/lib/atcoder' 4 | 5 | def get_language_id(extname, contest_date) 6 | # TODO: 日付の検証 7 | if contest_date < Date.new(2015, 3, 1) 8 | # ABC001 ~ ABC019 9 | case extname 10 | when '.rb' 11 | # Ruby (1.9.3) 12 | 9 13 | when '.cpp' 14 | # C++11 (GCC 4.8.1) 15 | 10 16 | when '.c' 17 | # C (GCC 4.6.4) 18 | 13 19 | when '.hs' 20 | # Haskell (GHC 7.4.1) 21 | 11 22 | else 23 | raise "Unknown extname: #{extname}" 24 | end 25 | elsif contest_date < Date.new(2016, 3, 20) 26 | # ABC020 ~ ABC 034 27 | case extname 28 | when '.rb' 29 | # Ruby (2.1.5p273) 30 | 2010 31 | when '.cpp' 32 | # C++11 (GCC 4.9.2) 33 | 2003 34 | when '.c' 35 | # C (GCC 4.9.2) 36 | 2001 37 | when '.hs' 38 | # Haskell (Haskell Platform 2014.2.0.0) 39 | 2033 40 | else 41 | raise "Unknown extname: #{extname}" 42 | end 43 | else 44 | # ABC035~ 45 | case extname 46 | when '.rb' 47 | # Ruby (2.3.0) 48 | 3024 49 | when '.cpp' 50 | # C++14 (GCC 5.3.0) 51 | 3003 52 | when '.c' 53 | # C (GCC 5.3.0) 54 | 3002 55 | when '.hs' 56 | # Haskell (GHC 7.10) 57 | 3014 58 | else 59 | raise "Unknown extname: #{extname}" 60 | end 61 | end 62 | end 63 | 64 | module AtcoderGreedy 65 | class Command < Thor 66 | desc 'submit [SUBMIT_FILE]', 'submit your solution' 67 | 68 | # TODO: 提出言語のオプション 69 | map 's' => 'submit' 70 | def submit(submit_file) 71 | print "Submit [#{submit_file}] ... " 72 | contest_info = YAML.load_file("./.contest_info.yml") 73 | problem = File.basename(submit_file, '.*') 74 | if contest_info[:task].include?(:"#{problem}") 75 | task_id = contest_info[:task][:"#{problem}"][:id] 76 | else 77 | raise "Unknown problem: #{problem}" 78 | end 79 | 80 | atcoder = Atcoder.new 81 | atcoder.login(contest_info[:url]) 82 | 83 | submit_url = contest_info[:url] + "/submit?task_id=#{task_id}" 84 | atcoder.agent.get(submit_url) do |page| 85 | p = page.form_with(action: "/submit?task_id=#{task_id}") do |f| 86 | f.field_with(name: 'source_code').value = File.open(submit_file).read 87 | f.field_with(name: 'task_id').value = task_id 88 | 89 | # 日付情報が書いていなかった場合取得する 90 | if contest_info[:date].nil? 91 | contest_info[:date] = Date.parse(page.xpath('//time').first.text) 92 | File.open("./.contest_info.yml", 'w') do |f| 93 | f.puts contest_info.to_yaml 94 | end 95 | end 96 | f.field_with(name: "language_id_#{task_id}").value = 97 | get_language_id(File.extname(submit_file), contest_info[:date]) 98 | end.submit 99 | puts 'Done!' 100 | Launchy.open p.uri 101 | end 102 | end 103 | end 104 | end -------------------------------------------------------------------------------- /lib/atcoder_greedy/command/template.rb: -------------------------------------------------------------------------------- 1 | require 'atcoder_greedy' 2 | require 'atcoder_greedy/command' 3 | require 'atcoder_greedy/lib/greedy_template' 4 | 5 | module AtcoderGreedy 6 | class Command < Thor 7 | desc 'template [OPTION]', 'set template' 8 | option :add, aliases: '-a' 9 | option :list, aliases: '-l' 10 | option :set_default, aliases: '-s' 11 | option :delete, aliases: '-d' 12 | def template 13 | temp = GreedyTemplate.new 14 | if options[:add] 15 | temp.add(options[:add]) 16 | elsif options[:list] 17 | temp.list 18 | elsif options[:set_default] 19 | temp.set_default(options[:set_default]) 20 | elsif options[:delete] 21 | temp.delete(options[:delete]) 22 | end 23 | end 24 | end 25 | end 26 | 27 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/command/test.rb: -------------------------------------------------------------------------------- 1 | require 'atcoder_greedy' 2 | require 'atcoder_greedy/command' 3 | require 'atcoder_greedy/lib/test_case' 4 | 5 | module AtcoderGreedy 6 | class Command < Thor 7 | desc 'test [PROBLEM_FILE_NAME]', 'test your solution' 8 | 9 | map 't' => 'test' 10 | def test(problem_name) 11 | TestCase.new(problem_name).validate 12 | end 13 | end 14 | end 15 | 16 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/lib/atcoder.rb: -------------------------------------------------------------------------------- 1 | require 'mechanize' 2 | require 'atcoder_greedy' 3 | 4 | class Atcoder 5 | attr_accessor :agent 6 | def initialize 7 | @agent = Mechanize.new 8 | end 9 | 10 | def login(url) 11 | print 'Login ... ' 12 | if AtcoderGreedy.config[:user_id].nil? || AtcoderGreedy.config[:user_id].size == 0 13 | puts 'You still not set account info.' 14 | print 'Input User id: ' 15 | user_id = $stdin.gets.chomp! 16 | print 'Input password: ' 17 | password = $stdin.gets.chomp! 18 | else 19 | user_id = AtcoderGreedy.config[:user_id] 20 | password = AtcoderGreedy.config[:password] 21 | end 22 | 23 | response = nil 24 | @agent.get(url + '/login') do |page| 25 | response = page.form_with(action: '/login') do |f| 26 | f.field_with(name: 'name').value = user_id 27 | f.field_with(name: 'password').value = password 28 | end.submit 29 | raise 'Login error' unless response.response['x-imojudge-simpleauth'] == 'Passed' 30 | end 31 | puts 'Done!' 32 | response 33 | end 34 | end -------------------------------------------------------------------------------- /lib/atcoder_greedy/lib/contest.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | require 'cgi' 3 | require 'atcoder_greedy/lib/atcoder' 4 | require 'atcoder_greedy' 5 | require 'atcoder_greedy/lib/greedy_template' 6 | 7 | class Contest 8 | attr_accessor :name, :url, :dir, :problems, :date 9 | 10 | def initialize(url, **options) 11 | if options[:language] != '' 12 | @language = options[:language] 13 | else 14 | @language = AtcoderGreedy.config[:language] 15 | end 16 | @url = url 17 | 18 | set_agent 19 | set_contest_info(options[:problems]) 20 | set_directories(options[:directory]) 21 | 22 | create_inputs unless options[:no][:input] 23 | create_templates(options[:template]) unless options[:no][:template] 24 | 25 | puts 'Set up done. Go for it!' 26 | end 27 | 28 | def set_agent 29 | atcoder = Atcoder.new 30 | atcoder.login(@url) 31 | @agent = atcoder.agent 32 | end 33 | 34 | def set_contest_info(option_problems) 35 | print 'Set contest info ... ' 36 | @name = URI.parse(@url).host.split('.').first 37 | html = @agent.get(@url + '/assignments').content.toutf8 38 | doc = Nokogiri::HTML.parse(html, nil, 'utf8') 39 | @date = Date.parse(doc.xpath('//time').first.text) 40 | 41 | all_problems = [] 42 | task_ids = [] 43 | doc.xpath('//tbody').each do |tbody| 44 | tbody.xpath('.//a[starts-with(@href,"/submit")]').each do |a| 45 | task_ids.push(CGI.parse(URI.parse(a.attributes['href'].value).query)['task_id'].first) 46 | end 47 | all_problems = tbody.xpath('.//a[@class="linkwrapper"]') 48 | end 49 | 50 | @problems = [] 51 | if all_problems.nil? 52 | raise 'Failed to get info. Do you participate this contest?' 53 | else 54 | until all_problems.empty? 55 | path = all_problems[0].attributes['href'].value 56 | pro = all_problems.select { |l| l.attributes['href'].value == path } 57 | all_problems = all_problems.reject { |l| l.attributes['href'].value == path } 58 | name = pro[0].inner_text 59 | if option_problems.empty? || (!option_problems.empty? && option_problems.include?(name)) 60 | @problems.push(name: pro[0].inner_text, path: path, task_id: task_ids.shift) 61 | print "#{name} " 62 | end 63 | end 64 | end 65 | puts 'Done!' 66 | end 67 | 68 | def create_inputs 69 | print 'Create inputs ... ' 70 | @problems.each do |problem| 71 | # take input and output params from url and save to file 72 | html = @agent.get(@url + problem[:path]).content.toutf8 73 | doc = Nokogiri::HTML.parse(html, nil, 'utf8') 74 | in_file = File.new(@dir + "/input_#{problem[:name]}.txt", 'w') 75 | 76 | params = doc.xpath('//pre') 77 | params.shift 78 | params.each_with_index do |p, i| 79 | if i % 2 == 0 80 | in_file.puts "-- Example #{i/2}" 81 | in_file.puts "#{p.text.gsub(/\r\n?/, "\n").strip}" 82 | else 83 | in_file.puts "-- Answer #{(i-1)/2}" 84 | in_file.puts "#{p.text.gsub(/\r\n?/, "\n").strip}" 85 | end 86 | end 87 | 88 | in_file.close 89 | end 90 | puts 'Done!' 91 | end 92 | 93 | def create_templates(option_template) 94 | print 'Create Templates ... ' 95 | if option_template.to_s == '' 96 | # use system default or user default template 97 | if AtcoderGreedy.config[:default_template][:"#{@language}"].nil? || AtcoderGreedy.config[:default_template][:"#{@language}"].to_s == '' 98 | solve_template = open(File.dirname(__dir__) + '/templates' + "/#{@language}/solve.#{@language}", &:read) 99 | else 100 | solve_template = open(AtcoderGreedy.config[:default_template][:"#{@language}"], &:read) 101 | end 102 | else 103 | # use option_template 104 | template_path = GreedyTemplate.get_template_path(option_template) 105 | if template_path.nil? 106 | raise "ERROR: Template #{option_template} doesn't found" 107 | else 108 | solve_template = open(template_path, &:read) 109 | end 110 | end 111 | 112 | @problems.each_with_index do |problem| 113 | solve_file_content = solve_template.clone 114 | solve_file_content.gsub!(/DATE/, Time.now.strftime('%F')) 115 | solve_file_content.gsub!(/CONTEST/, @name.upcase) 116 | solve_file_content.gsub!(/PROBLEM/, problem[:name]) 117 | solve_file = File.new(@dir + "/#{problem[:name]}.#{@language}", 'w') 118 | solve_file.print solve_file_content 119 | solve_file.close 120 | end 121 | puts 'Done!' 122 | end 123 | 124 | def set_directories(directory) 125 | print 'Set contest directory ... ' 126 | if directory.to_s == '' 127 | FileUtils.mkdir(@name) 128 | @dir = "./#{@name}" 129 | else 130 | if Dir.exists?(directory) 131 | @dir = directory 132 | else 133 | raise "ERROR: Directory doesn't exists:#{@dir}" 134 | end 135 | end 136 | puts 'Done!' 137 | end 138 | end -------------------------------------------------------------------------------- /lib/atcoder_greedy/lib/greedy_template.rb: -------------------------------------------------------------------------------- 1 | require 'atcoder_greedy' 2 | 3 | class GreedyTemplate 4 | def initialize 5 | @dir = AtcoderGreedy::get_config_path + '/templates' 6 | Dir.mkdir(@dir) unless Dir.exists?(@dir) 7 | end 8 | 9 | def add(file_path) 10 | # save template to language directory 11 | file = File.open(file_path) 12 | file_name = File.basename(file_path) 13 | type_dir = @dir + '/' + File.extname(file_path).delete('.') 14 | Dir.mkdir(type_dir) unless Dir.exists?(type_dir) 15 | if File.exists?(type_dir + '/' + file_name) 16 | print "Template [#{file_name}] is already exists. Do you update?[y/N]:" 17 | s = $stdin.gets.chomp 18 | if s == 'y' || s == 'yes' 19 | FileUtils.cp(file, type_dir) 20 | puts 'Template file is updated.' 21 | puts "if you want to use this file as a default, please run 'atcoder_greedy template -s #{file_name}'" 22 | end 23 | else 24 | FileUtils.cp(file, type_dir) 25 | puts 'Template file is added.' 26 | puts "if you want to use this file as a default, please run 'atcoder_greedy template -s #{file_name}'" 27 | end 28 | end 29 | 30 | def list 31 | puts "Show Template file lists. [d] is this language default. ---------------------" 32 | Dir::glob(@dir + '/*').each do |l| 33 | puts "#{File.basename(l)}:" 34 | Dir::glob("#{l}/*").each do |f| 35 | default = get_default(File.basename(l)) 36 | if default != nil && File.basename(f) == default 37 | print ' [d] ' 38 | else 39 | print ' - ' 40 | end 41 | puts "#{File.basename(f)}" 42 | end 43 | end 44 | end 45 | 46 | def set_default(file_name) 47 | type = File.extname(file_name).delete('.') 48 | type_dir = @dir + '/' + type 49 | file = type_dir + '/' + File.basename(file_name) 50 | if File.exists?(file) 51 | AtcoderGreedy.configure(default_template: {"#{type}": file}) 52 | puts 'Set new default template.' 53 | else 54 | puts "File [#{file_name}] doesn't exists. confirm input name." 55 | self.list 56 | end 57 | end 58 | 59 | def delete(file_name) 60 | type = File.extname(file_name).delete('.') 61 | type_dir = @dir + '/' + type 62 | file = type_dir + '/' + File.basename(file_name) 63 | if File.exists?(file) 64 | print "Do you delete [#{file_name}]?[y/N]:" 65 | s = $stdin.gets.chomp 66 | if s == 'y' || s == 'yes' 67 | if File.basename(file_name) == get_default(type) 68 | AtcoderGreedy.configure(default_template: {"#{type}": ''}) 69 | end 70 | FileUtils.remove_file(file) 71 | puts 'Template file is deleted.' 72 | end 73 | else 74 | puts "File [#{file_name}] doesn't exists. confirm input name." 75 | self.list 76 | end 77 | end 78 | 79 | def self.get_template_path(file_name) 80 | type = File.extname(file_name).delete('.') 81 | type_dir = AtcoderGreedy::get_config_path + '/templates' + '/' + type 82 | file = type_dir + '/' + File.basename(file_name) 83 | File.exists?(file) ? file : nil 84 | end 85 | 86 | private 87 | def get_default(language) 88 | unless AtcoderGreedy.config[:default_template][:"#{language}"].nil? 89 | File.basename(AtcoderGreedy.config[:default_template][:"#{language}"]) 90 | end 91 | end 92 | end -------------------------------------------------------------------------------- /lib/atcoder_greedy/lib/languages.rb: -------------------------------------------------------------------------------- 1 | class Languages 2 | ALL_LANGUAGES = %w(rb cpp c hs) 3 | def initialize(solve_file) 4 | @solve_file = solve_file 5 | end 6 | 7 | def compile(problem_name) 8 | raise 'Error: Not Implemented' 9 | end 10 | 11 | def execute(input_path, output_path) 12 | raise 'Error: Not Implemented' 13 | end 14 | end 15 | 16 | class Rb < Languages 17 | def compile(problem_name) 18 | true 19 | end 20 | 21 | def execute(input_path, output_path) 22 | system "ruby #{@solve_file} < #{input_path} > #{output_path}" 23 | end 24 | end 25 | 26 | class Cpp < Languages 27 | def compile(problem_name) 28 | @exec_file = "#{problem_name}.out" 29 | system "g++ #{@solve_file} -o #{problem_name}.out" 30 | end 31 | 32 | def execute(input_path, output_path) 33 | system "./#{@exec_file} < #{input_path} > #{output_path}" 34 | end 35 | end 36 | 37 | class C < Languages 38 | def compile(problem_name) 39 | @exec_file = "#{problem_name}.out" 40 | system "gcc #{@solve_file} -o #{problem_name}.out" 41 | end 42 | 43 | def execute(input_path, output_path) 44 | system "./#{@exec_file} < #{input_path} > #{output_path}" 45 | end 46 | end 47 | 48 | class Hs < Languages 49 | def compile(problem_name) 50 | @exec_file = "#{problem_name}.out" 51 | system "ghc #{@solve_file} -o #{problem_name}.out" 52 | end 53 | 54 | def execute(input_path, output_path) 55 | system "./#{@exec_file} < #{input_path} > #{output_path}" 56 | end 57 | end -------------------------------------------------------------------------------- /lib/atcoder_greedy/lib/test_case.rb: -------------------------------------------------------------------------------- 1 | require 'diff/lcs' 2 | require 'tempfile' 3 | require 'benchmark' 4 | require 'atcoder_greedy/lib/languages' 5 | 6 | class TestCase 7 | def initialize(problem_name) 8 | language = File.extname(problem_name) 9 | if language.size == 0 10 | language = '.' + AtcoderGreedy.config[:language] 11 | problem_name = problem_name + language 12 | end 13 | puts "Running a test for problem #{problem_name}..." 14 | 15 | @problem_name = File.basename(problem_name, '.*') 16 | @input_file = File.open("./input_#{@problem_name}.txt", 'r') 17 | @exec_file = "./#{@problem_name}#{language}" 18 | get_in_out 19 | end 20 | 21 | def get_in_out 22 | i = 0 23 | @input = [] 24 | @output = [] 25 | now = nil 26 | while (t = @input_file.gets) != nil 27 | example_string = "-- Example #{i}" 28 | answer_string = "-- Answer #{i}" 29 | 30 | if t.chomp == example_string 31 | now.close(false) unless now.nil? 32 | now = Tempfile.new(['in', '.txt'], './') 33 | @input.push(now) 34 | now.open 35 | elsif t.chomp == answer_string 36 | now.close(false) unless now.nil? 37 | now = Tempfile.new(['out', '.txt'], './') 38 | @output.push(now) 39 | now.open 40 | i += 1 41 | else 42 | now.puts t 43 | end 44 | end 45 | @input[-1].close(false) 46 | @output[-1].close(false) 47 | end 48 | 49 | def validate 50 | my_solve = get_solve(@exec_file) 51 | passed = 0 52 | begin 53 | if my_solve.compile(@problem_name) 54 | puts '-------------------- Compile Done --------------------' 55 | else 56 | raise 'Compile Error' 57 | end 58 | 59 | @input.size.times do |j| 60 | myout_file = Tempfile.new(['myout', '.txt'], './') 61 | myout_file.open 62 | result = Benchmark.realtime do 63 | unless my_solve.execute(@input[j].path, myout_file.path) 64 | raise "Runtime Error" 65 | end 66 | @input[j].close 67 | myout_file.close(false) 68 | end 69 | 70 | myout = myout_file.open.read 71 | myout_file.close 72 | correct = File.open("#{@output[j].path}").read 73 | diffs = Diff::LCS.diff(myout, correct) 74 | if diffs.size == 0 75 | passed += 1 76 | puts "-------------------- Testcase ##{j + 1} -------------------- PASSED! Time: #{sprintf("%.5f", result)}s" 77 | else 78 | puts "-------------------- Testcase ##{j + 1} -------------------- FAILED! Time: #{sprintf("%.5f", result)}s" 79 | puts 'Your Output:' 80 | puts "#{myout}\n" 81 | puts 'Correct Answer:' 82 | puts "#{correct}\n" 83 | end 84 | end 85 | puts "Test done. #{passed}/#{@input.size} passed." 86 | rescue => e 87 | puts e 88 | end 89 | end 90 | 91 | # HACK: move to Languages 92 | def get_solve(solve_file) 93 | case File.extname(solve_file) 94 | when '.rb' 95 | Rb.new(solve_file) 96 | when '.cpp' 97 | Cpp.new(solve_file) 98 | when '.c' 99 | C.new(solve_file) 100 | when '.hs' 101 | Hs.new(solve_file) 102 | else 103 | raise 'Unknown Language' 104 | end 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/settings.yml: -------------------------------------------------------------------------------- 1 | user_id: '' 2 | password: '' 3 | language: 'rb' -------------------------------------------------------------------------------- /lib/atcoder_greedy/templates/c/solve.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Generated by AtcoderGreedy on DATE 3 | * CONTEST PROBLEM 4 | */ 5 | 6 | #include 7 | 8 | void solve() { 9 | // Your code here 10 | } 11 | 12 | int main(void) { 13 | solve(); 14 | return 0; 15 | } -------------------------------------------------------------------------------- /lib/atcoder_greedy/templates/cpp/solve.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Generated by AtcoderGreedy on DATE 3 | * CONTEST PROBLEM 4 | */ 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | void solve() { 11 | // Your code here 12 | } 13 | 14 | int main(void) { 15 | solve(); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/templates/hs/solve.hs: -------------------------------------------------------------------------------- 1 | -- Your function here 2 | 3 | main :: IO () 4 | main = do -------------------------------------------------------------------------------- /lib/atcoder_greedy/templates/py/solve.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keigo-brook/atcoder_greedy/4c466f521e1327280a8de5aed1996b94dc3295e3/lib/atcoder_greedy/templates/py/solve.py -------------------------------------------------------------------------------- /lib/atcoder_greedy/templates/rb/solve.rb: -------------------------------------------------------------------------------- 1 | # Generated by AtcoderGreedy on DATE 2 | # CONTEST PROBLEM 3 | # Your code here 4 | -------------------------------------------------------------------------------- /lib/atcoder_greedy/version.rb: -------------------------------------------------------------------------------- 1 | module AtcoderGreedy 2 | VERSION = '0.6.0' 3 | end 4 | -------------------------------------------------------------------------------- /spec/commands/create_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'atcoder_greedy' 3 | describe 'Command::create' do 4 | after(:all) do 5 | if Dir.exist?("./abc003") 6 | FileUtils.rm_rf('./abc003') 7 | end 8 | end 9 | subject { ->(url) { AtcoderGreedy::Command.new.create(url) } } 10 | it 'should create contest files' do 11 | allow(AtcoderGreedy).to receive(:config).and_return( 12 | { 13 | user_id: '', 14 | password: '', 15 | language: '', 16 | default_template: { 17 | rb: '', 18 | cpp: '', 19 | c: '', 20 | py: '' 21 | } 22 | }) 23 | # subject.call('http://abc003.contest.atcoder.jp') 24 | # expect("a").to exist("") 25 | # TODO ログイン情報どうするか考える 26 | 27 | end 28 | end -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rspec --init` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause 4 | # this file to always be loaded, without a need to explicitly require it in any 5 | # files. 6 | # 7 | # Given that it is always loaded, you are encouraged to keep this file as 8 | # light-weight as possible. Requiring heavyweight dependencies from this file 9 | # will add to the boot time of your test suite on EVERY test run, even for an 10 | # individual file that may not need all of that loaded. Instead, consider making 11 | # a separate helper file that requires the additional dependencies and performs 12 | # the additional setup, and require it from the spec files that actually need 13 | # it. 14 | # 15 | # The `.rspec` file also contains a few flags that are not defaults but that 16 | # users commonly want. 17 | # 18 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 19 | require 'rspec' 20 | RSpec.configure do |config| 21 | # rspec-expectations config goes here. You can use an alternate 22 | # assertion/expectation library such as wrong or the stdlib/minitest 23 | # assertions if you prefer. 24 | config.expect_with :rspec do |expectations| 25 | # This option will default to `true` in RSpec 4. It makes the `description` 26 | # and `failure_message` of custom matchers include text for helper methods 27 | # defined using `chain`, e.g.: 28 | # be_bigger_than(2).and_smaller_than(4).description 29 | # # => "be bigger than 2 and smaller than 4" 30 | # ...rather than: 31 | # # => "be bigger than 2" 32 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 33 | end 34 | 35 | # rspec-mocks config goes here. You can use an alternate test double 36 | # library (such as bogus or mocha) by changing the `mock_with` option here. 37 | config.mock_with :rspec do |mocks| 38 | # Prevents you from mocking or stubbing a method that does not exist on 39 | # a real object. This is generally recommended, and will default to 40 | # `true` in RSpec 4. 41 | mocks.verify_partial_doubles = true 42 | end 43 | 44 | # The settings below are suggested to provide a good initial experience 45 | # with RSpec, but feel free to customize to your heart's content. 46 | =begin 47 | # These two settings work together to allow you to limit a spec run 48 | # to individual examples or groups you care about by tagging them with 49 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 50 | # get run. 51 | config.filter_run :focus 52 | config.run_all_when_everything_filtered = true 53 | 54 | # Allows RSpec to persist some state between runs in order to support 55 | # the `--only-failures` and `--next-failure` CLI options. We recommend 56 | # you configure your source control system to ignore this file. 57 | config.example_status_persistence_file_path = "spec/examples.txt" 58 | 59 | # Limits the available syntax to the non-monkey patched syntax that is 60 | # recommended. For more details, see: 61 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ 62 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 63 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode 64 | config.disable_monkey_patching! 65 | 66 | # This setting enables warnings. It's recommended, but in some cases may 67 | # be too noisy due to issues in dependencies. 68 | config.warnings = true 69 | 70 | # Many RSpec users commonly either run the entire suite or an individual 71 | # file, and it's useful to allow more verbose output when running an 72 | # individual spec file. 73 | if config.files_to_run.one? 74 | # Use the documentation formatter for detailed output, 75 | # unless a formatter has already been configured 76 | # (e.g. via a command-line flag). 77 | config.default_formatter = 'doc' 78 | end 79 | 80 | # Print the 10 slowest examples and example groups at the 81 | # end of the spec run, to help surface which specs are running 82 | # particularly slow. 83 | config.profile_examples = 10 84 | 85 | # Run specs in random order to surface order dependencies. If you find an 86 | # order dependency and want to debug it, you can fix the order by providing 87 | # the seed, which is printed after each run. 88 | # --seed 1234 89 | config.order = :random 90 | 91 | # Seed global randomization in this process using the `--seed` CLI option. 92 | # Setting this allows you to use `--seed` to deterministically reproduce 93 | # test failures related to randomization by passing the same `--seed` value 94 | # as the one that triggered the failure. 95 | Kernel.srand config.seed 96 | =end 97 | end 98 | --------------------------------------------------------------------------------