et 0.5.8 → 0.7.2

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.8)
4
+ et (0.6.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,6 +3,7 @@ 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"
@@ -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.length) 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,10 +51,6 @@ 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
56
  def config
@@ -40,7 +40,7 @@ module ET
40
40
  desc "List available lessons."
41
41
  command :list do |c|
42
42
  c.action do |_global_options, _options, _cmdargs|
43
- Formatter.print_table(api.list_lessons, :slug, :title, :type)
43
+ Formatter.print_table(api.list_lessons, 'slug', 'title', 'type')
44
44
  end
45
45
  end
46
46
 
@@ -49,7 +49,7 @@ module ET
49
49
  c.action do |_global_options, _options, cmdargs|
50
50
  cmdargs.each do |slug|
51
51
  lesson = api.get_lesson(slug)
52
- archive = api.download_file(lesson[:archive_url])
52
+ archive = api.download_file(lesson['archive_url'])
53
53
  archive_manager = ET::ArchiveManager.new(archive, cwd)
54
54
  archive_manager.unpack
55
55
 
@@ -0,0 +1,57 @@
1
+ require "rake/file_list"
2
+
3
+ module ET
4
+ class SubmissionFileList
5
+ include Enumerable
6
+ DEFAULT_IGNORE_GLOBS = [
7
+ '.lesson.yml',
8
+ 'node_modules/'
9
+ ]
10
+
11
+ def initialize(path)
12
+ @path = path
13
+ end
14
+
15
+ def files
16
+ unless @files
17
+ @files = Rake::FileList[File.join(@path, "**/*"), File.join(@path, ".etignore")]
18
+ ignore_globs.each do |glob|
19
+ filename = File.join(@path, glob)
20
+
21
+ if File.directory?(filename)
22
+ filename += glob.end_with?("/") ? "**/*" : "/**/*"
23
+ end
24
+
25
+ @files = @files.exclude(filename)
26
+ end
27
+ @files = @files.sub(File.join(@path, "/"), "")
28
+ end
29
+
30
+ @files
31
+ end
32
+
33
+ def each(&block)
34
+ files.each do |file|
35
+ block.call(file)
36
+ end
37
+ end
38
+
39
+ protected
40
+ def ignore_globs
41
+ etignore_globs + [] + DEFAULT_IGNORE_GLOBS
42
+ end
43
+
44
+ def etignore_globs
45
+ unless @etignore_globs
46
+ etignore = File.join(@path, '.etignore')
47
+ if FileTest.exists?(etignore)
48
+ @etignore_globs = File.read(etignore).split(/\n/)
49
+ @etignore_globs.delete_if { | string | string.start_with?("#") || string.empty?}
50
+ else
51
+ @etignore_globs = []
52
+ end
53
+ end
54
+ @etignore_globs
55
+ end
56
+ end
57
+ end
@@ -1,3 +1,3 @@
1
1
  module ET
2
- VERSION = "0.5.8"
2
+ VERSION = "0.7.2"
3
3
  end
@@ -1,38 +1,38 @@
1
- describe "get lesson" do
1
+ describe 'get lesson' do
2
2
  let(:lesson_info) do
3
3
  {
4
- title: "Some Challenge",
5
- slug: "some-challenge",
6
- archive_url: "http://localhost:3000/some-challenge.tar.gz"
4
+ 'title' => 'Some Challenge',
5
+ 'slug' => 'some-challenge',
6
+ 'archive_url' => "http://localhost:3000/some-challenge.tar.gz"
7
7
  }
8
8
  end
9
9
 
10
10
  let(:sample_archive_path) do
11
- project_root.join("spec/data/some-challenge.tar.gz")
11
+ project_root.join('spec/data/some-challenge.tar.gz')
12
12
  end
13
13
 
14
- context "when in a working area" do
15
- it "downloads and extracts the lesson" do
16
- tmp_archive_path = File.join(Dir.tmpdir, "some-challenge.tar.gz")
17
- system("cp", sample_archive_path.to_s, tmp_archive_path)
14
+ context 'when in a working area' do
15
+ it 'downloads and extracts the lesson' do
16
+ tmp_archive_path = File.join(Dir.tmpdir, 'some-challenge.tar.gz')
17
+ system('cp', sample_archive_path.to_s, tmp_archive_path)
18
18
 
19
19
  expect_any_instance_of(ET::API).to receive(:get_lesson).
20
- with("some-challenge").
20
+ with('some-challenge').
21
21
  and_return(lesson_info)
22
22
 
23
23
  expect_any_instance_of(ET::API).to receive(:download_file).
24
- with("http://localhost:3000/some-challenge.tar.gz").
24
+ with('http://localhost:3000/some-challenge.tar.gz').
25
25
  and_return(tmp_archive_path)
26
26
 
27
- Dir.mktmpdir("test") do |tmpdir|
27
+ Dir.mktmpdir('test') do |tmpdir|
28
28
  write_sample_config_to(tmpdir)
29
29
 
30
30
  runner = ET::Runner.new(tmpdir)
31
31
  _, _ = capture_output do
32
- expect(runner.go(["get", "some-challenge"])).to eq(0)
32
+ expect(runner.go(['get', 'some-challenge'])).to eq(0)
33
33
  end
34
34
 
35
- ["some-challenge/README.md", "some-challenge/sample.rb"].each do |filename|
35
+ ['some-challenge/README.md', 'some-challenge/sample.rb'].each do |filename|
36
36
  path = File.join(tmpdir, filename)
37
37
  expect(File.exist?(path)).to eq(true)
38
38
  end