codewars_cli 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +107 -0
- data/Rakefile +11 -0
- data/bin/codewars +9 -0
- data/codewars_cli.gemspec +32 -0
- data/lib/codewars_cli.rb +17 -0
- data/lib/codewars_cli/cli.rb +29 -0
- data/lib/codewars_cli/client.rb +8 -0
- data/lib/codewars_cli/concerns/attributes_methods.rb +18 -0
- data/lib/codewars_cli/config.rb +41 -0
- data/lib/codewars_cli/configuration.rb +55 -0
- data/lib/codewars_cli/deferred.rb +57 -0
- data/lib/codewars_cli/file_creator.rb +68 -0
- data/lib/codewars_cli/file_parser_helpers.rb +33 -0
- data/lib/codewars_cli/finalize.rb +26 -0
- data/lib/codewars_cli/generic_helpers.rb +33 -0
- data/lib/codewars_cli/kata.rb +28 -0
- data/lib/codewars_cli/language.rb +14 -0
- data/lib/codewars_cli/presenter.rb +81 -0
- data/lib/codewars_cli/runner.rb +55 -0
- data/lib/codewars_cli/submit_kata.rb +45 -0
- data/lib/codewars_cli/templates/description.erb +34 -0
- data/lib/codewars_cli/user.rb +22 -0
- data/lib/codewars_cli/version.rb +3 -0
- metadata +188 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 622cacf0166844f7f9de6053724b756a3e8cd2ce
|
4
|
+
data.tar.gz: 5da61b3297094e17efdf8979144eec32c3217b73
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a826ffa99620707ae31cd56884e09aa4dc39ef7d54e9868e80f8d2c555e6a2eeb55373965936d7815d8ed9919ca9fddae922925358045460c0fdd95b622d9310
|
7
|
+
data.tar.gz: d49f0d316b83921babb8d727ab0405a464a6711ccb8b5610ff97befceee541bb45e83a6731093931d57cc3054787ee00daf97386132e65f6d639a5ba862f6525
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 GustavoCaso
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
![Travis Build](https://travis-ci.org/GustavoCaso/codewars_cli.svg?branch=master)
|
2
|
+
# CodewarsCli
|
3
|
+
|
4
|
+
With this command you would be able to enjoy [Codewars](http://www.codewars.com/), a site where you can practice your coding skills
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
```
|
9
|
+
gem install codewars_cli
|
10
|
+
```
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
The start working you would need an account in [Codewars](http://www.codewars.com/join), if you have it already great!.
|
15
|
+
To start using the CLI you will need setup up a few things first.
|
16
|
+
|
17
|
+
##Comands
|
18
|
+
|
19
|
+
### Configuration
|
20
|
+
There are a few commands you can use to configuration your CLI, the most important one is to setup your api_key, first you will need to get it from your account of [Codewars](https://www.codewars.com/users/edit).
|
21
|
+
|
22
|
+
To setup your api_key `codewars config api_key YOUR_API_KEY`.
|
23
|
+
|
24
|
+
There are other options you can configure **language** and **folder**.
|
25
|
+
|
26
|
+
The language is your favorite option for downloading. Also you can specify everytime you start a new session what language you want use.
|
27
|
+
|
28
|
+
To setup your language `codewars config language LANGUAGE`.
|
29
|
+
|
30
|
+
### Valid Languages
|
31
|
+
|
32
|
+
```
|
33
|
+
ruby
|
34
|
+
javascript
|
35
|
+
java
|
36
|
+
coffeescript
|
37
|
+
haskell
|
38
|
+
clojure
|
39
|
+
c
|
40
|
+
python
|
41
|
+
```
|
42
|
+
|
43
|
+
|
44
|
+
The folder option is where all your description file will be downloaded.
|
45
|
+
|
46
|
+
The file structure will be: `~/YOUR_FOLDER/#{NAME_OF_THE_KATA}/#{LANGUAGE}`
|
47
|
+
|
48
|
+
To setup your language `codewars config folder FOLDER`.
|
49
|
+
|
50
|
+
Once you have finish the setup up, you can changed but you will have to pass a flag `update` to tell the application to overwrite it.
|
51
|
+
|
52
|
+
##### Example
|
53
|
+
|
54
|
+
To overwrite your api_key `codewars config api_key YOUR_API_KEY --update`.
|
55
|
+
|
56
|
+
### User
|
57
|
+
Display all the information related to a Codewars user in your Terminal.
|
58
|
+
|
59
|
+
`codewars user USERNAME_OR_ID` will display the information well formatted for your eyes.
|
60
|
+
|
61
|
+
![User_dispay_info](https://cloud.githubusercontent.com/assets/4672858/12372466/8bb2e012-bc58-11e5-8fac-325108ebfdf6.png)
|
62
|
+
|
63
|
+
### Next Kata
|
64
|
+
Start a new session of training and download all the information related to a new kata.
|
65
|
+
This command will create a `description.md` file with all the information of the Kata and some metadata that is need it for submiting the kata later.
|
66
|
+
|
67
|
+
Also it will create a `solution.{LANGUAGE_EXTENSION}` file where you should place your code in other to be uploaded when submitting the kata.
|
68
|
+
|
69
|
+
`codewars next_kata` [Valid languages](#valid-languages)
|
70
|
+
|
71
|
+
To specify a a different language just add a new param as the language you want to train.
|
72
|
+
|
73
|
+
`codewars next_kata javascript`
|
74
|
+
|
75
|
+
### Submit Kata
|
76
|
+
When submitting a kata, the application will upload your code to the Codewars server and will wait for the server to respond with the result, depending on the respond, the kata could be **finalized** or keep working on it.
|
77
|
+
|
78
|
+
To submit use `codewars submit KATA_NAME`
|
79
|
+
|
80
|
+
By Default it will use you predefined language, but you can always specify a different one:
|
81
|
+
|
82
|
+
`codewars submit KATA_NAME --language=LANGUAGE` [Valid languages](#valid-languages)
|
83
|
+
|
84
|
+
|
85
|
+
In case the name is not correct it will display a formatted list with all your katas order by language to help you.
|
86
|
+
|
87
|
+
### Finalize
|
88
|
+
This is the last step of the process.
|
89
|
+
|
90
|
+
To finish a kata type `codewars finalize KATA_NAME`
|
91
|
+
|
92
|
+
As well you can specify the language of the kata `codewars finalize KATA_NAME --language=LANGUAGE` [Valid languages](#valid-languages)
|
93
|
+
|
94
|
+
It will close the kata four you.
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
## Contributing
|
100
|
+
|
101
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/GustavoCaso/codewars_cli. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
102
|
+
|
103
|
+
|
104
|
+
## License
|
105
|
+
|
106
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
107
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require 'cucumber'
|
4
|
+
require 'cucumber/rake/task'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
8
|
+
t.cucumber_opts = "features --format pretty -x"
|
9
|
+
end
|
10
|
+
|
11
|
+
task :default => :spec
|
data/bin/codewars
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'codewars_cli/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "codewars_cli"
|
8
|
+
spec.version = CodewarsCli::VERSION
|
9
|
+
spec.authors = ["GustavoCaso"]
|
10
|
+
spec.email = ["gustavocaso@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{CLI tool to interact with codewars in the comfort of your terminal}
|
13
|
+
spec.description = %q{CLI tool to interact with codewars in the comfort of your terminal,
|
14
|
+
allow you to fetch users information, kata, upload solutions and close it.
|
15
|
+
}
|
16
|
+
spec.homepage = "https://github.com/GustavoCaso/codewars_cli"
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
spec.executables = Dir['bin/*'].map { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_runtime_dependency 'thor'
|
24
|
+
spec.add_runtime_dependency "codewars_client"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "rspec"
|
29
|
+
spec.add_development_dependency "aruba"
|
30
|
+
spec.add_development_dependency "pry"
|
31
|
+
spec.add_development_dependency 'webmock'
|
32
|
+
end
|
data/lib/codewars_cli.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'codewars_client'
|
3
|
+
require 'codewars_cli/file_parser_helpers'
|
4
|
+
require "codewars_cli/generic_helpers"
|
5
|
+
require "codewars_cli/presenter"
|
6
|
+
require 'codewars_cli/file_creator'
|
7
|
+
require 'codewars_cli/finalize'
|
8
|
+
require 'codewars_cli/deferred'
|
9
|
+
require "codewars_cli/submit_kata"
|
10
|
+
require "codewars_cli/kata"
|
11
|
+
require "codewars_cli/user"
|
12
|
+
require "codewars_cli/client"
|
13
|
+
require 'codewars_cli/language'
|
14
|
+
require "codewars_cli/configuration"
|
15
|
+
require "codewars_cli/config"
|
16
|
+
require "codewars_cli/cli"
|
17
|
+
require "codewars_cli/version"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module CodewarsCli
|
2
|
+
class Cli < Thor
|
3
|
+
desc 'config SUBCOMMAND ...ARGS', 'Write options in the configuration file'
|
4
|
+
subcommand 'config', Config
|
5
|
+
|
6
|
+
desc 'user USERNAME_OR_ID', 'return user information'
|
7
|
+
def user(username_or_id)
|
8
|
+
User.fetch(username_or_id).print_description
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'next_kata', 'start a new session training session and create markdown page with kata information'
|
12
|
+
option :language, banner: " ruby | c | javascript | java | coffescript | haskell | clojure"
|
13
|
+
def next_kata
|
14
|
+
Kata.fetch(options[:language]).create_file
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'submit_kata', 'upload solution to codewars'
|
18
|
+
option :language, banner: 'The language of the kata if not provided will get the deafult one'
|
19
|
+
def submit_kata(kata_name)
|
20
|
+
SubmitKata.find(kata_name, options[:language]).upload_kata
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'finalize', 'finalize kata'
|
24
|
+
option :language, banner: 'The language of the kata if not provided will get the deafult one'
|
25
|
+
def finalize(kata_name)
|
26
|
+
Finalize.find(kata_name, options[:language])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module CodewarsCli
|
2
|
+
module Concerns
|
3
|
+
module AttributesMethods
|
4
|
+
def attributes
|
5
|
+
_build_attributes(self)
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def _build_attributes(object)
|
11
|
+
object.instance_variables.inject({}) do |hash, key|
|
12
|
+
hash[key.to_s.gsub('@', '').to_sym] = object.instance_variable_get(key)
|
13
|
+
hash
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module CodewarsCli
|
2
|
+
class Config < Thor
|
3
|
+
desc 'api_key KEY', 'Set the global configuration for api_key'
|
4
|
+
method_options update: :boolean
|
5
|
+
def api_key(api_key)
|
6
|
+
Configuration.write(api_key, :api_key, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
desc 'language LANGUAGE', 'Set the global configuration for language'
|
10
|
+
long_desc <<-LONGDESC
|
11
|
+
`language LANGUAGE` will store the prefer language for trainnig katas.
|
12
|
+
|
13
|
+
Available options are:\n
|
14
|
+
- Ruby\n
|
15
|
+
- Javascript\n
|
16
|
+
- Java\n
|
17
|
+
- Coffescript\n
|
18
|
+
- Haskell\n
|
19
|
+
- C#\n
|
20
|
+
- Python\n
|
21
|
+
- Clojure\n
|
22
|
+
LONGDESC
|
23
|
+
method_options update: :boolean
|
24
|
+
def language(language)
|
25
|
+
Configuration.write(language, :language, options)
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'folder FOLDER', 'Set the global configuration for folder where all the kata information will be stored'
|
29
|
+
long_desc <<-LONGDESC
|
30
|
+
`folder FOLDER` will store the prefer location for file information.
|
31
|
+
|
32
|
+
It will create a folder for each language that you train,
|
33
|
+
containing the markdown file with all the information about the kata,
|
34
|
+
and the file to complete the kata
|
35
|
+
LONGDESC
|
36
|
+
method_options update: :boolean
|
37
|
+
def folder(folder)
|
38
|
+
Configuration.write(folder, :folder, options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
module CodewarsCli
|
3
|
+
module Configuration
|
4
|
+
include GenericHelpers
|
5
|
+
CONFIG_FILE = '.codewars.rc.yml'
|
6
|
+
CONFIG_CONTENTS = {
|
7
|
+
api_key: '',
|
8
|
+
language: '',
|
9
|
+
folder: '',
|
10
|
+
}
|
11
|
+
|
12
|
+
def self.write(value, key, options)
|
13
|
+
create_config_file unless File.exists? config_file
|
14
|
+
update_value(value, key) && return if options['update'] && !send(key).empty?
|
15
|
+
if !send(key).empty?
|
16
|
+
info "Do you want to overwrite #{key} provide --update option"
|
17
|
+
else
|
18
|
+
info "Updating config file with #{key}: #{value}"
|
19
|
+
update_value(value, key)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.update_value(value, key)
|
24
|
+
content = config_data
|
25
|
+
content.send(:[]=, key, value)
|
26
|
+
File.open(config_file, 'w') do |f|
|
27
|
+
f.write(content.to_yaml)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.create_config_file
|
32
|
+
File.open(config_file, 'w+') { |f| f.write(CONFIG_CONTENTS.to_yaml) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.api_key
|
36
|
+
config_data[:api_key] if config_data
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.language
|
40
|
+
config_data[:language] if config_data
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.folder
|
44
|
+
config_data[:folder] if config_data
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.config_file
|
48
|
+
File.join(ENV['HOME'], CONFIG_FILE)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.config_data
|
52
|
+
YAML::load_file(config_file) if File.exists? config_file
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module CodewarsCli
|
2
|
+
class Deferred
|
3
|
+
include GenericHelpers
|
4
|
+
REQUEST_TIMES = 10
|
5
|
+
attr_reader :kata_name, :language, :response, :client
|
6
|
+
def initialize(kata_name, language, response, client)
|
7
|
+
@kata_name = kata_name
|
8
|
+
@language = language
|
9
|
+
@response = response
|
10
|
+
@client = client
|
11
|
+
_read_deferred do
|
12
|
+
info('Your solution has been uploaded waiting for results')
|
13
|
+
_handle_deferred_response(_handle_deferred)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def _read_deferred
|
20
|
+
if response.success
|
21
|
+
yield
|
22
|
+
else
|
23
|
+
error('There has been an error uploading the kata please try agin later')
|
24
|
+
error("Reason: #{response.reason}")
|
25
|
+
exit(1)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def _handle_deferred_response(result)
|
30
|
+
_display_info_for_unsubmitted_result if result.nil? || !result.success
|
31
|
+
|
32
|
+
if result.valid
|
33
|
+
info 'The solution has passed all tests on the server.'
|
34
|
+
info 'If you are happy with your solution please type'
|
35
|
+
info "codewars finalize #{kata_name} --language=#{language}", :blue
|
36
|
+
else
|
37
|
+
error 'The solution has not passed tests on the server. Response:'
|
38
|
+
error(result.reason)
|
39
|
+
exit(1)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def _display_info_for_unsubmitted_result
|
44
|
+
error("Can't get a result of tests on the server. Try it again.")
|
45
|
+
exit(1)
|
46
|
+
end
|
47
|
+
|
48
|
+
def _handle_deferred
|
49
|
+
REQUEST_TIMES.times do
|
50
|
+
result = client.deferred_response(dmid: response.dmid)
|
51
|
+
return result if result.success
|
52
|
+
sleep 1
|
53
|
+
end
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module CodewarsCli
|
5
|
+
class FileCreator
|
6
|
+
include GenericHelpers
|
7
|
+
DESCRIPTION_FILE_NAME = 'description.md'
|
8
|
+
def self.create(kata_info, language)
|
9
|
+
folder_path = Configuration.folder
|
10
|
+
fail Thor::Error, "ERROR: You must config the folder\nSOLUTION: Set up with `config folder FOLDER_LOCATION`" if folder_path.empty?
|
11
|
+
new(kata_info, language, folder_path).create_file
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :data, :language, :folder_path
|
15
|
+
def initialize(data, language, folder_path)
|
16
|
+
@data = extend_object(data)
|
17
|
+
@language = language
|
18
|
+
@folder_path = folder_path
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_file
|
22
|
+
_create_missing_dirs unless File.exists?(_destination_path)
|
23
|
+
_fill_template_with_kata_info
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def _create_missing_dirs
|
29
|
+
FileUtils.mkdir_p(_destination_path)
|
30
|
+
end
|
31
|
+
|
32
|
+
def _fill_template_with_kata_info
|
33
|
+
b = _create_binding
|
34
|
+
template = File.read(File.expand_path('../templates/description.erb', __FILE__))
|
35
|
+
content = ERB.new(template).result(b)
|
36
|
+
_create_markdown_file(content)
|
37
|
+
end
|
38
|
+
|
39
|
+
def _create_binding
|
40
|
+
b = binding
|
41
|
+
(data.attributes.merge({language: language})).each do |k,v|
|
42
|
+
b.local_variable_set(k.to_sym, v)
|
43
|
+
end
|
44
|
+
b
|
45
|
+
end
|
46
|
+
|
47
|
+
def _create_markdown_file(content)
|
48
|
+
Dir.chdir(_destination_path) do
|
49
|
+
info("Creating Kata descrition file")
|
50
|
+
File.open(DESCRIPTION_FILE_NAME,'w') { |f| f.write content }
|
51
|
+
info("Creating Kata solution file")
|
52
|
+
File.open(_solution_file_name, 'w+')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def _solution_file_name
|
57
|
+
"solution.#{_language_extension}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def _language_extension
|
61
|
+
CodewarsCli::Language::EXTENSIONS[language]
|
62
|
+
end
|
63
|
+
|
64
|
+
def _destination_path
|
65
|
+
File.join(ENV['HOME'],folder_path,data.slug,language)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module CodewarsCli
|
4
|
+
module FileParserHelpers
|
5
|
+
def _parse_description_file(kata_name, language)
|
6
|
+
Dir.chdir(_kata_path(kata_name, language)) do
|
7
|
+
description_content = File.read(FileCreator::DESCRIPTION_FILE_NAME)
|
8
|
+
project_id = _fetch_info(description_content, 'Project ID')
|
9
|
+
solution_id = _fetch_info(description_content, 'Solution ID')
|
10
|
+
OpenStruct.new(project_id: project_id, solution_id: solution_id)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def _fetch_info(content, string)
|
15
|
+
regex = %r(#{string}: (.*))
|
16
|
+
if match = content.match(regex)
|
17
|
+
match[1]
|
18
|
+
else
|
19
|
+
error("The #{string} is missing from your description.md")
|
20
|
+
exit(1)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def _kata_path(kata_name, language)
|
25
|
+
path = File.join(ENV['HOME'], Configuration.folder, kata_name, language)
|
26
|
+
unless File.exist?(path)
|
27
|
+
presenter.display_katas_info(kata_name, language)
|
28
|
+
exit(1)
|
29
|
+
end
|
30
|
+
path
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module CodewarsCli
|
2
|
+
class Finalize
|
3
|
+
include GenericHelpers
|
4
|
+
include FileParserHelpers
|
5
|
+
def self.find(kata_name, language)
|
6
|
+
check_for_api_key
|
7
|
+
new(kata_name, language).finalize
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :kata_name, :language
|
11
|
+
|
12
|
+
def initialize(kata_name, language)
|
13
|
+
@kata_name = kata_name
|
14
|
+
@language = language || Configuration.language
|
15
|
+
end
|
16
|
+
|
17
|
+
def finalize
|
18
|
+
response = client.finalize(kata: _parse_description_file(kata_name, language))
|
19
|
+
if response.success
|
20
|
+
info('Your Kata has been uploaded and finish')
|
21
|
+
else
|
22
|
+
error("There has been an error finalizing your kata #{response.reason}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'codewars_cli/concerns/attributes_methods'
|
2
|
+
module CodewarsCli
|
3
|
+
module GenericHelpers
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(self)
|
6
|
+
end
|
7
|
+
|
8
|
+
def check_for_api_key
|
9
|
+
fail Thor::Error ,"ERROR: You must config the api_key\nSOLUTION: Set up with `config api_key KEY`" if Configuration.api_key.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def client
|
13
|
+
@client ||= Client.connection
|
14
|
+
end
|
15
|
+
|
16
|
+
def extend_object(object)
|
17
|
+
object.extend(Concerns::AttributesMethods)
|
18
|
+
object
|
19
|
+
end
|
20
|
+
|
21
|
+
def info(msg, color=:green)
|
22
|
+
presenter.info(msg, color)
|
23
|
+
end
|
24
|
+
|
25
|
+
def error(msg)
|
26
|
+
presenter.error(msg)
|
27
|
+
end
|
28
|
+
|
29
|
+
def presenter
|
30
|
+
@presenter ||= Presenter.new
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module CodewarsCli
|
2
|
+
class Kata
|
3
|
+
include GenericHelpers
|
4
|
+
def self.fetch(language)
|
5
|
+
check_for_api_key
|
6
|
+
if language
|
7
|
+
new(language)
|
8
|
+
else
|
9
|
+
default_language = Configuration.language
|
10
|
+
fail Thor::Error, "ERROR: You must config the language for this command\nSOLUTION: Set up with `config language LANGUAGE`" if default_language.empty?
|
11
|
+
new(default_language)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :language
|
16
|
+
def initialize(language)
|
17
|
+
@language = language
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_kata
|
21
|
+
client.next_kata(language: language)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_file
|
25
|
+
FileCreator.create(get_kata, language)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module CodewarsCli
|
2
|
+
class Presenter < Thor
|
3
|
+
include GenericHelpers
|
4
|
+
no_commands do
|
5
|
+
def display_user_info(object)
|
6
|
+
return error(_user_error_message(object)) unless object.status == 200
|
7
|
+
info("Displaying information about #{object.username}", :magenta)
|
8
|
+
object = extend_object(object)
|
9
|
+
attr = object.attributes
|
10
|
+
languague_attributes = attr.delete(:languages)
|
11
|
+
attr.each do |k,v|
|
12
|
+
_print_attributes(k,v)
|
13
|
+
end
|
14
|
+
print_table(_build_column_info(languague_attributes))
|
15
|
+
end
|
16
|
+
|
17
|
+
def display_katas_info(kata_name, language)
|
18
|
+
error("There is no kata with that name '#{kata_name}' and language '#{language}'")
|
19
|
+
info('To help here is a list of all your katas order by language', :magenta)
|
20
|
+
_katas_info.each do |language, katas|
|
21
|
+
_print_attributes(language, katas.join(','))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def info(message, color)
|
26
|
+
say set_color(message, color)
|
27
|
+
end
|
28
|
+
|
29
|
+
def error(message)
|
30
|
+
say set_color(message, :red)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def _katas_info
|
37
|
+
Dir.chdir(_katas_folder) do
|
38
|
+
Dir.glob('**/*').select do |fn|
|
39
|
+
File.directory?(fn) && fn.include?('/')
|
40
|
+
end.map{|arr| arr.split('/')}.inject({}) do |hash, arr|
|
41
|
+
hash[arr.last.to_sym] = []
|
42
|
+
hash[arr.last.to_sym] << arr.first
|
43
|
+
hash
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def _katas_folder
|
49
|
+
File.join(ENV['HOME'], Configuration.folder)
|
50
|
+
end
|
51
|
+
|
52
|
+
def _user_error_message(object)
|
53
|
+
"ERROR: Fetching Information\nREASON: #{object.reason.upcase}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def _build_column_info(info)
|
57
|
+
info.inject([_set_headers]) do |arr, (key,value)|
|
58
|
+
arr << [
|
59
|
+
set_color(key, :yellow),
|
60
|
+
value.values.map{|v| set_color(v, :blue)}
|
61
|
+
].flatten
|
62
|
+
arr
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def _set_headers
|
67
|
+
['languages', 'rank', 'name', 'color', 'score'].map {|h| set_color(h, :green)}
|
68
|
+
end
|
69
|
+
|
70
|
+
def _print_attributes(key, value, indent = false )
|
71
|
+
if value.is_a? Hash
|
72
|
+
say set_color("#{key}:", :yellow) + "\n"
|
73
|
+
value.each { |k,v| _print_attributes(k,v, true) }
|
74
|
+
else
|
75
|
+
line = set_color("#{key}: ", :green) + set_color("#{value}", :blue) + "\n"
|
76
|
+
line = " #{line}" if indent
|
77
|
+
say line
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'codewars_cli'
|
2
|
+
|
3
|
+
# to use Webmock we need the Runner class
|
4
|
+
# https://github.com/cucumber/aruba#testing-ruby-cli-programs-without-spawning-a-new-ruby-process
|
5
|
+
module CodewarsCli
|
6
|
+
class Runner
|
7
|
+
def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
|
8
|
+
init_pry
|
9
|
+
@argv = argv
|
10
|
+
@stdin = stdin
|
11
|
+
@stdout = stdout
|
12
|
+
@stderr = stderr
|
13
|
+
@kernel = kernel
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute!
|
17
|
+
exit_code = run_cli
|
18
|
+
@kernel.exit(exit_code)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def init_pry
|
24
|
+
require 'pry'
|
25
|
+
Pry.config.output = STDOUT # without this Pry does't work properly
|
26
|
+
rescue LoadError
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def run_cli
|
31
|
+
exit_code = begin
|
32
|
+
$stderr = @stderr
|
33
|
+
$stdin = @stdin
|
34
|
+
$stdout = @stdout
|
35
|
+
|
36
|
+
CodewarsCli::Cli.start(@argv)
|
37
|
+
|
38
|
+
0
|
39
|
+
rescue StandardError => e
|
40
|
+
b = e.backtrace
|
41
|
+
@stderr.puts("#{b.shift}: #{e.message} (#{e.class})")
|
42
|
+
@stderr.puts(b.map { |s| "\tfrom #{s}" }.join("\n"))
|
43
|
+
1
|
44
|
+
rescue SystemExit => e
|
45
|
+
e.status
|
46
|
+
ensure
|
47
|
+
$stderr = STDERR
|
48
|
+
$stdin = STDIN
|
49
|
+
$stdout = STDOUT
|
50
|
+
end
|
51
|
+
|
52
|
+
@kernel.exit(exit_code)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module CodewarsCli
|
2
|
+
class SubmitKata
|
3
|
+
include GenericHelpers
|
4
|
+
include FileParserHelpers
|
5
|
+
def self.find(kata_name, language)
|
6
|
+
check_for_api_key
|
7
|
+
if kata_name
|
8
|
+
new(kata_name, language)
|
9
|
+
else
|
10
|
+
error("ERROR: You must provide the name of the kata")
|
11
|
+
exit(1)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :kata_name, :language
|
16
|
+
|
17
|
+
def initialize(kata_name, language)
|
18
|
+
@kata_name = kata_name
|
19
|
+
@language = language || Configuration.language
|
20
|
+
end
|
21
|
+
|
22
|
+
def upload_kata
|
23
|
+
code = _get_kata_solution_code(kata_name, language)
|
24
|
+
response = client.attemp_solution(kata: _parse_description_file(kata_name, language), code: code)
|
25
|
+
Deferred.new(kata_name, language, response, client)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def _get_kata_solution_code(kata_name, language)
|
31
|
+
Dir.chdir(_kata_path(kata_name, language)) do
|
32
|
+
File.read(_solution_file)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def _solution_file
|
37
|
+
"solution.#{_language_extension}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def _language_extension
|
41
|
+
CodewarsCli::Language::EXTENSIONS[language]
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Meta Information
|
2
|
+
Project ID: <%= project_id %>
|
3
|
+
|
4
|
+
Solution ID: <%= solution_id %>
|
5
|
+
|
6
|
+
# Kata Description
|
7
|
+
|
8
|
+
Name: <%= name %>
|
9
|
+
|
10
|
+
Author: <%= author %>
|
11
|
+
|
12
|
+
Rank: <%= rank %>
|
13
|
+
|
14
|
+
Slug: <%= slug %>
|
15
|
+
|
16
|
+
Tags: <%= tags.join(', ') %>
|
17
|
+
|
18
|
+
## Task
|
19
|
+
|
20
|
+
<%= description %>
|
21
|
+
|
22
|
+
## Code
|
23
|
+
|
24
|
+
```<%= language %>
|
25
|
+
<%= setup %>
|
26
|
+
```
|
27
|
+
<% unless example_fixture.empty? %>
|
28
|
+
## Test Example
|
29
|
+
|
30
|
+
```<%= language %>
|
31
|
+
<%= example_fixture %>
|
32
|
+
```
|
33
|
+
<% end %>
|
34
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module CodewarsCli
|
2
|
+
class User
|
3
|
+
include GenericHelpers
|
4
|
+
def self.fetch(username_or_id)
|
5
|
+
check_for_api_key
|
6
|
+
new(username_or_id)
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :username_or_id
|
10
|
+
def initialize(username_or_id)
|
11
|
+
@username_or_id = username_or_id
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_user
|
15
|
+
client.user(username_or_id: username_or_id)
|
16
|
+
end
|
17
|
+
|
18
|
+
def print_description
|
19
|
+
presenter.display_user_info(get_user)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: codewars_cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- GustavoCaso
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: codewars_client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.10'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.10'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
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: aruba
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webmock
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: "CLI tool to interact with codewars in the comfort of your terminal,\n
|
126
|
+
\ allow you to fetch users information, kata, upload solutions
|
127
|
+
and close it.\n "
|
128
|
+
email:
|
129
|
+
- gustavocaso@gmail.com
|
130
|
+
executables:
|
131
|
+
- codewars
|
132
|
+
extensions: []
|
133
|
+
extra_rdoc_files: []
|
134
|
+
files:
|
135
|
+
- ".gitignore"
|
136
|
+
- ".rspec"
|
137
|
+
- ".travis.yml"
|
138
|
+
- CODE_OF_CONDUCT.md
|
139
|
+
- Gemfile
|
140
|
+
- LICENSE.txt
|
141
|
+
- README.md
|
142
|
+
- Rakefile
|
143
|
+
- bin/codewars
|
144
|
+
- codewars_cli.gemspec
|
145
|
+
- lib/codewars_cli.rb
|
146
|
+
- lib/codewars_cli/cli.rb
|
147
|
+
- lib/codewars_cli/client.rb
|
148
|
+
- lib/codewars_cli/concerns/attributes_methods.rb
|
149
|
+
- lib/codewars_cli/config.rb
|
150
|
+
- lib/codewars_cli/configuration.rb
|
151
|
+
- lib/codewars_cli/deferred.rb
|
152
|
+
- lib/codewars_cli/file_creator.rb
|
153
|
+
- lib/codewars_cli/file_parser_helpers.rb
|
154
|
+
- lib/codewars_cli/finalize.rb
|
155
|
+
- lib/codewars_cli/generic_helpers.rb
|
156
|
+
- lib/codewars_cli/kata.rb
|
157
|
+
- lib/codewars_cli/language.rb
|
158
|
+
- lib/codewars_cli/presenter.rb
|
159
|
+
- lib/codewars_cli/runner.rb
|
160
|
+
- lib/codewars_cli/submit_kata.rb
|
161
|
+
- lib/codewars_cli/templates/description.erb
|
162
|
+
- lib/codewars_cli/user.rb
|
163
|
+
- lib/codewars_cli/version.rb
|
164
|
+
homepage: https://github.com/GustavoCaso/codewars_cli
|
165
|
+
licenses:
|
166
|
+
- MIT
|
167
|
+
metadata: {}
|
168
|
+
post_install_message:
|
169
|
+
rdoc_options: []
|
170
|
+
require_paths:
|
171
|
+
- lib
|
172
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
requirements: []
|
183
|
+
rubyforge_project:
|
184
|
+
rubygems_version: 2.4.6
|
185
|
+
signing_key:
|
186
|
+
specification_version: 4
|
187
|
+
summary: CLI tool to interact with codewars in the comfort of your terminal
|
188
|
+
test_files: []
|