et 0.5.9 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1 @@
1
- 2.2.3
1
+ 2.6.3
@@ -1,39 +1,44 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- et (0.5.9)
4
+ et (0.7.2)
5
+ faraday (~> 0.9)
6
+ faraday_middleware (~> 0.10)
5
7
  gli (= 2.11.0)
6
8
  multipart-post (~> 2.0)
9
+ rake (~> 10)
7
10
  rspec (~> 3.0)
8
11
  rspec-mocks (~> 3.0)
9
12
 
10
13
  GEM
11
14
  remote: https://rubygems.org/
12
15
  specs:
13
- coderay (1.1.1)
14
- diff-lcs (1.2.5)
16
+ coderay (1.1.2)
17
+ diff-lcs (1.3)
18
+ faraday (0.17.3)
19
+ multipart-post (>= 1.2, < 3)
20
+ faraday_middleware (0.14.0)
21
+ faraday (>= 0.7.4, < 1.0)
15
22
  gli (2.11.0)
16
- method_source (0.8.2)
17
- multipart-post (2.0.0)
18
- pry (0.10.3)
19
- coderay (~> 1.1.0)
20
- method_source (~> 0.8.1)
21
- slop (~> 3.4)
23
+ method_source (1.0.0)
24
+ multipart-post (2.1.1)
25
+ pry (0.13.1)
26
+ coderay (~> 1.1)
27
+ method_source (~> 1.0)
22
28
  rake (10.5.0)
23
- rspec (3.4.0)
24
- rspec-core (~> 3.4.0)
25
- rspec-expectations (~> 3.4.0)
26
- rspec-mocks (~> 3.4.0)
27
- rspec-core (3.4.4)
28
- rspec-support (~> 3.4.0)
29
- rspec-expectations (3.4.0)
29
+ rspec (3.9.0)
30
+ rspec-core (~> 3.9.0)
31
+ rspec-expectations (~> 3.9.0)
32
+ rspec-mocks (~> 3.9.0)
33
+ rspec-core (3.9.2)
34
+ rspec-support (~> 3.9.3)
35
+ rspec-expectations (3.9.2)
30
36
  diff-lcs (>= 1.2.0, < 2.0)
31
- rspec-support (~> 3.4.0)
32
- rspec-mocks (3.4.1)
37
+ rspec-support (~> 3.9.0)
38
+ rspec-mocks (3.9.1)
33
39
  diff-lcs (>= 1.2.0, < 2.0)
34
- rspec-support (~> 3.4.0)
35
- rspec-support (3.4.1)
36
- slop (3.6.0)
40
+ rspec-support (~> 3.9.0)
41
+ rspec-support (3.9.3)
37
42
 
38
43
  PLATFORMS
39
44
  ruby
@@ -41,7 +46,6 @@ PLATFORMS
41
46
  DEPENDENCIES
42
47
  et!
43
48
  pry (~> 0)
44
- rake (~> 10)
45
49
 
46
50
  BUNDLED WITH
47
- 1.12.5
51
+ 1.17.2
data/README.md CHANGED
@@ -28,3 +28,20 @@ COMMANDS
28
28
  submit - Submit the lesson in this directory.
29
29
  test - Run an exercise test suite.
30
30
  ```
31
+
32
+ ### Releasing New Versions
33
+
34
+ Bundler provided `gem_tasks` have been incorporated into this libraries
35
+ `Rakefile`. Thankfully these tasks make releasing new gem versions a snap!
36
+
37
+ To release a new version of this gem:
38
+
39
+ 1. Bump the version according to [semantic versioning](http://semver.org/)
40
+ 2. Perform a git commit
41
+ 3. Run `rake release` from the project root
42
+
43
+ Bundler's provided rake task will appropriately push a tag to GitHub and the gem
44
+ itself to [rubygems.org](https://rubygems.org)
45
+
46
+ _Note:_ in order to release the gem you must be an authorized owner of it on
47
+ [rubygems.org](https://rubygems.org)
data/et.gemspec CHANGED
@@ -15,14 +15,15 @@ DESC
15
15
 
16
16
  s.files = `git ls-files`.split("\n")
17
17
  s.require_paths << "lib"
18
- s.has_rdoc = false
19
18
  s.bindir = "bin"
20
19
  s.executables << "et"
21
20
  s.license = "MIT"
22
- s.add_development_dependency("rake", "~> 10")
23
21
  s.add_development_dependency("pry", '~> 0')
24
22
  s.add_runtime_dependency("rspec", "~> 3.0")
23
+ s.add_runtime_dependency("rake", "~> 10")
25
24
  s.add_runtime_dependency("rspec-mocks", "~> 3.0")
26
25
  s.add_runtime_dependency("multipart-post", "~> 2.0")
27
26
  s.add_runtime_dependency("gli", "2.11.0")
27
+ s.add_runtime_dependency("faraday", "~> 0.9")
28
+ s.add_runtime_dependency("faraday_middleware", "~> 0.10")
28
29
  end
data/lib/et.rb CHANGED
@@ -3,9 +3,8 @@ require_relative "et/version"
3
3
  require_relative "et/runner"
4
4
  require_relative "et/operating_system"
5
5
  require_relative "et/api"
6
+ require_relative "et/submission_file_list"
6
7
  require_relative "et/config"
7
8
  require_relative "et/formatter"
8
9
  require_relative "et/lesson"
9
- require_relative "et/challenge"
10
- require_relative "et/exercise"
11
10
  require_relative "et/archive_manager"
@@ -1,9 +1,9 @@
1
- require "net/http/post/multipart"
2
1
  require "securerandom"
3
2
  require "base64"
4
3
  require "json"
5
4
  require "openssl"
6
5
 
6
+ require_relative "fallback_connection"
7
7
  module ET
8
8
  class API
9
9
  attr_reader :host, :username, :token
@@ -15,30 +15,29 @@ module ET
15
15
  end
16
16
 
17
17
  def list_lessons
18
- request = Net::HTTP::Get.new(lessons_url)
19
- request["Authorization"] = auth_header
20
-
21
- response = issue_request(request)
22
- JSON.parse(response.body, symbolize_names: true)[:lessons]
18
+ response = nil
19
+ api_client.open do |client|
20
+ response = client.get('/lessons.json', :submittable => 1)
21
+ end
22
+ response.body['lessons']
23
23
  end
24
24
 
25
25
  def get_lesson(slug)
26
- request = Net::HTTP::Get.new(lesson_url(slug))
27
- request["Authorization"] = auth_header
28
-
29
- response = issue_request(request)
30
-
31
- body = JSON.parse(response.body, symbolize_names: true)
32
- body[:lesson]
26
+ resp = nil
27
+ api_client.open do |client|
28
+ resp = client.get(lesson_url(slug), :submittable => 1)
29
+ end
30
+ resp.body['lesson']
33
31
  end
34
32
 
35
33
  def download_file(url)
36
- uri = URI(url)
34
+ response = nil
37
35
  dest = random_filename
38
36
 
39
- request = Net::HTTP::Get.new(uri.path)
40
- response = issue_request(request, url)
41
- if response.code == "200"
37
+ download_client(url).open do |client|
38
+ response = client.get(URI(url).path)
39
+ end
40
+ if response.status == 200
42
41
  open(dest, 'wb') do |file|
43
42
  file.write(response.body)
44
43
  end
@@ -50,66 +49,47 @@ module ET
50
49
 
51
50
  def submit_lesson(lesson)
52
51
  submission_file = lesson.archive!
53
- url = submission_url(lesson.slug)
54
-
55
- File.open(submission_file) do |f|
56
- request = Net::HTTP::Post::Multipart.new(url.path,
57
- "submission[archive]" => UploadIO.new(f, "application/x-tar", "archive.tar.gz"))
58
- request["Authorization"] = auth_header
59
-
60
- issue_request(request)
52
+ io = Faraday::UploadIO.new(submission_file, "application/x-tar")
53
+ resp = nil
54
+ api_client.open do |client|
55
+ resp = client.post(submission_url(lesson.slug),
56
+ "submission" => { "archive" => io})
61
57
  end
58
+ resp
62
59
  end
63
60
 
64
61
  private
65
- def issue_request(request, url = nil)
66
- uri = URI.parse(url || @host)
67
- begin
68
- Net::HTTP.start(uri.host, uri.port,
69
- use_ssl: uri.scheme == "https") do |http|
70
-
71
- http.request(request)
72
- end
73
- rescue OpenSSL::SSL::SSLError => e
74
- if operating_system.platform_family?(:windows)
75
- https = Net::HTTP.new(uri.host, uri.port)
76
- https.verify_mode = OpenSSL::SSL::VERIFY_NONE
77
- https.use_ssl = uri.scheme == 'https'
78
- https.start do |http|
79
- http.request(request)
80
- end
81
- else
82
- raise e
83
- end
84
- end
85
- end
86
-
87
62
  def lesson_url(slug)
88
- URI.join(host, "lessons/#{slug}.json?submittable=1")
89
- end
90
-
91
- def lessons_url
92
- URI.join(host, "lessons.json?submittable=1")
63
+ "/lessons/#{slug}.json"
93
64
  end
94
65
 
95
66
  def submission_url(slug)
96
- URI.join(host, "lessons/#{slug}/submissions.json")
67
+ "/lessons/#{slug}/submissions.json"
97
68
  end
98
69
 
99
70
  def random_filename
100
71
  File.join(Dir.mktmpdir, SecureRandom.hex)
101
72
  end
102
73
 
103
- def credentials
104
- Base64.strict_encode64("#{username}:#{token}")
105
- end
74
+ def api_client
75
+ @api_client ||= ET::FallbackConnection.new(:url => @host) do |client|
76
+ client.request :multipart
106
77
 
107
- def auth_header
108
- "Basic #{credentials}"
78
+ client.request :url_encoded
79
+ client.request :basic_auth, username, token
80
+
81
+ client.response :json, :content_type => /\bjson$/
82
+
83
+ client.adapter Faraday.default_adapter
84
+ end
109
85
  end
110
86
 
111
- def operating_system
112
- @os ||= ET::OperatingSystem.new
87
+ def download_client(url)
88
+ uri = URI(url)
89
+ scheme_and_host = [uri.scheme, uri.host].join('://')
90
+ ET::FallbackConnection.new(:url => scheme_and_host) do |client|
91
+ client.adapter Faraday.default_adapter
92
+ end
113
93
  end
114
94
  end
115
95
  end
@@ -0,0 +1,29 @@
1
+ require "faraday"
2
+ require "faraday_middleware"
3
+
4
+ module ET
5
+ class FallbackConnection
6
+ def initialize(opts = {}, &block)
7
+ @connection = Faraday.new(opts, &block)
8
+
9
+ @fallback_connection = Faraday.new(opts.merge(:ssl => {:verify => false}), &block)
10
+ end
11
+
12
+ def open(&block)
13
+ begin
14
+ block.call(@connection)
15
+ rescue Faraday::SSLError => e
16
+ if operating_system.platform_family?(:windows)
17
+ block.call(@fallback_connection)
18
+ else
19
+ raise e
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+ def operating_system
26
+ @os ||= ET::OperatingSystem.new
27
+ end
28
+ end
29
+ end
@@ -17,16 +17,16 @@ module ET
17
17
  File.open(filepath, "wb") do |file|
18
18
  Zlib::GzipWriter.wrap(file) do |gz|
19
19
  Gem::Package::TarWriter.new(gz) do |tar|
20
- Dir.glob(File.join(dir, "**/*")).each do |file|
21
- relative_path = file.gsub(dir + "/", "")
22
- if !ignored_files.include?(relative_path)
23
- if FileTest.directory?(file)
24
- tar.mkdir(relative_path, 0755)
25
- else
26
- file_contents = File.read(file)
27
- tar.add_file_simple("./" + relative_path, 0555, file_contents.bytesize) do |io|
28
- io.write(file_contents)
29
- end
20
+ ET::SubmissionFileList.new(dir).each do |file|
21
+ relative_path = file
22
+ absolute_path = File.join(dir, file)
23
+
24
+ if FileTest.directory?(absolute_path)
25
+ tar.mkdir(relative_path, 0755)
26
+ else
27
+ file_contents = File.read(absolute_path)
28
+ tar.add_file_simple("./" + relative_path, 0555, file_contents.bytesize) do |io|
29
+ io.write(file_contents)
30
30
  end
31
31
  end
32
32
  end
@@ -51,24 +51,16 @@ module ET
51
51
  !dir.nil?
52
52
  end
53
53
 
54
- def ignored_files
55
- (config["ignore"] || []) + [".lesson.yml"]
56
- end
57
-
58
54
  protected
59
55
 
60
- def config
61
- @config ||= YAML.load_file(File.join(dir, ".lesson.yml"))
62
- end
63
-
64
56
  def random_archive_path
65
57
  File.join(Dir.mktmpdir, "#{SecureRandom.hex}.tar.gz")
66
58
  end
67
59
 
68
60
  def find_lesson_dir(current_dir)
69
- path = File.join(current_dir, ".lesson.yml")
61
+ parent_directory = File.dirname(current_dir)
70
62
 
71
- if File.exists?(path)
63
+ if Config.new(parent_directory).exists?
72
64
  current_dir
73
65
  elsif current_dir == "." || Pathname.new(current_dir).root?
74
66
  nil
@@ -1,5 +1,4 @@
1
1
  require "gli"
2
- require "yaml"
3
2
 
4
3
  module ET
5
4
  class Runner
@@ -40,7 +39,7 @@ module ET
40
39
  desc "List available lessons."
41
40
  command :list do |c|
42
41
  c.action do |_global_options, _options, _cmdargs|
43
- Formatter.print_table(api.list_lessons, :slug, :title, :type)
42
+ Formatter.print_table(api.list_lessons, 'slug', 'title', 'type')
44
43
  end
45
44
  end
46
45
 
@@ -49,7 +48,7 @@ module ET
49
48
  c.action do |_global_options, _options, cmdargs|
50
49
  cmdargs.each do |slug|
51
50
  lesson = api.get_lesson(slug)
52
- archive = api.download_file(lesson[:archive_url])
51
+ archive = api.download_file(lesson['archive_url'])
53
52
  archive_manager = ET::ArchiveManager.new(archive, cwd)
54
53
  archive_manager.unpack
55
54
 
@@ -77,19 +76,6 @@ module ET
77
76
  end
78
77
  end
79
78
 
80
- desc "Run an exercise test suite."
81
- command :test do |c|
82
- c.action do |_global_options, _options, _cmdargs|
83
- exercise = Exercise.new(cwd)
84
-
85
- if exercise.exists?
86
- exercise.run_tests
87
- else
88
- raise StandardError.new("Not in an exercise directory.")
89
- end
90
- end
91
- end
92
-
93
79
  run(args)
94
80
  end
95
81
 
@@ -0,0 +1,58 @@
1
+ require "rake/file_list"
2
+
3
+ module ET
4
+ class SubmissionFileList
5
+ include Enumerable
6
+ DEFAULT_IGNORE_GLOBS = [
7
+ '.etignore',
8
+ 'node_modules/',
9
+ 'coverage/'
10
+ ]
11
+
12
+ def initialize(path)
13
+ @path = path
14
+ end
15
+
16
+ def files
17
+ unless @files
18
+ @files = Rake::FileList[File.join(@path, "**/*"), File.join(@path, ".etignore")]
19
+ ignore_globs.each do |glob|
20
+ filename = File.join(@path, glob)
21
+
22
+ if File.directory?(filename)
23
+ filename += glob.end_with?("/") ? "**/*" : "/**/*"
24
+ end
25
+
26
+ @files = @files.exclude(filename)
27
+ end
28
+ @files = @files.sub(File.join(@path, "/"), "")
29
+ end
30
+
31
+ @files
32
+ end
33
+
34
+ def each(&block)
35
+ files.each do |file|
36
+ block.call(file)
37
+ end
38
+ end
39
+
40
+ protected
41
+ def ignore_globs
42
+ etignore_globs + [] + DEFAULT_IGNORE_GLOBS
43
+ end
44
+
45
+ def etignore_globs
46
+ unless @etignore_globs
47
+ etignore = File.join(@path, '.etignore')
48
+ if FileTest.exists?(etignore)
49
+ @etignore_globs = File.read(etignore).split(/\n/)
50
+ @etignore_globs.delete_if { | string | string.start_with?("#") || string.empty?}
51
+ else
52
+ @etignore_globs = []
53
+ end
54
+ end
55
+ @etignore_globs
56
+ end
57
+ end
58
+ end