conference_tracker 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7286832479c6601a446e51d0ccb8b2cab5bce276
4
+ data.tar.gz: f76f784f392022aabd19e2a7ac0f4a52dcbc9479
5
+ SHA512:
6
+ metadata.gz: 0602d0efcc7c77d339becd15bb1fba3563240ec61e516cf7625612db03169d306499a65270fa4aade8e4b668f3e03ab5391725f1945bc348e46d087b66d67ba3
7
+ data.tar.gz: 5b1ac9dd0f19f1bbd4808b98dd8ed2479c565db77514538d9bf2cb7e1836bb39358055a6632b3f045196cf8cf00c2b41bd5e503a85badd0814260e8d0caf1888
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /*.gem
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in conference_tracker.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,112 @@
1
+ ## Table of Contents
2
+ * [Scope](#scope)
3
+ * [Design](#design)
4
+ * [SRP](#srp)
5
+ * [Installation](#installation)
6
+ * [Usage](#usage)
7
+ * [Library](#library)
8
+ * [CLI](#cli)
9
+
10
+ ## Scope
11
+ This gem is the Ruby implementation of the `Conference Track Management` code-kata.
12
+
13
+ ## Design
14
+
15
+ ### SRP
16
+ The code design follows the single responsibility principle by using a dedicated class for any specific task.
17
+
18
+ ## Installation
19
+ Install the gem from your shell:
20
+ ```shell
21
+ gem install conference_tracker
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### Library
27
+ Just require the library into your program and pass an array of notes to the converter:
28
+ ```ruby
29
+ require "conference_tracker"
30
+
31
+ talks = ["Writing Fast Tests Against Enterprise Rails 60min", "Overdoing it in Python 45min", "Lua for the Masses 30min", "Ruby Errors from Mismatched Gem Versions 45min", "Common Ruby Errors 45min"]
32
+
33
+ puts ConferenceTracker.call(talks)
34
+ # Track 1:
35
+ # 09:00AM Writing Fast Tests Against Enterprise Rails 60min
36
+ # 10:00AM Overdoing it in Python 45min
37
+ # 10:45AM Ruby Errors from Mismatched Gem Versions 45min
38
+ # 11:30AM Lua for the Masses 30min
39
+ # 12:00PM Lunch
40
+ # 01:00PM Common Ruby Errors 45min
41
+ # 04:00PM Networking Event
42
+ ```
43
+
44
+ ### CLI
45
+ The gem provides a CLI interface.
46
+ Once installed you will be able to use the `conference_tracker` command from the terminal.
47
+
48
+ #### Help
49
+ You can print CLI help by:
50
+ ```shell
51
+ conference_tracker -h
52
+ Usage: conference_tracker ~/talks.txt
53
+ -h --help Print this help
54
+ <path-to-file> Load conference talks
55
+ ```
56
+
57
+ #### Input
58
+ The program accepts as input a file containing the talks titles with their duration:
59
+ ```txt
60
+ # ~/talks.txt
61
+ Writing Fast Tests Against Enterprise Rails 60min
62
+ Overdoing it in Python 45min
63
+ Lua for the Masses 30min
64
+ Ruby Errors from Mismatched Gem Versions 45min
65
+ Common Ruby Errors 45min
66
+ Rails for Python Developers lightning
67
+ Communicating Over Distance 60min
68
+ Accounting-Driven Development 45min
69
+ Woah 30min
70
+ Sit Down and Write 30min
71
+ Pair Programming vs Noise 45min
72
+ Rails Magic 60min
73
+ Ruby on Rails: Why We Should Move On 60min
74
+ Clojure Ate Scala (on my project) 45min
75
+ Programming in the Boondocks of Seattle 30min
76
+ Ruby vs. Clojure for Back-End Development 30min
77
+ Ruby on Rails Legacy App Maintenance 60min
78
+ A World Without HackerNews 30min
79
+ User Interface CSS in Rails Apps 30min
80
+ ```
81
+
82
+ Just pass the file path to the program:
83
+ ```shell
84
+ conference_tracker ~/talks.txt
85
+ > Track 1:
86
+ > 09:00AM Rails Magic 60min
87
+ > 10:00AM Ruby on Rails: Why We Should Move On 60min
88
+ > 11:00AM Writing Fast Tests Against Enterprise Rails 60min
89
+ > 12:00PM Lunch
90
+ > 01:00PM Ruby on Rails Legacy App Maintenance 60min
91
+ > 02:00PM Communicating Over Distance 60min
92
+ > 03:00PM Ruby Errors from Mismatched Gem Versions 45min
93
+ > 03:45PM Pair Programming vs Noise 45min
94
+ > 04:30PM User Interface CSS in Rails Apps 30min
95
+ > 05:00PM Networking Event
96
+
97
+ > Track 2:
98
+ > 09:00AM Accounting-Driven Development 45min
99
+ > 09:45AM Clojure Ate Scala (on my project) 45min
100
+ > 10:30AM Common Ruby Errors 45min
101
+ > 11:15AM Overdoing it in Python 45min
102
+ > 12:00PM Lunch
103
+ > 01:00PM Lua for the Masses 30min
104
+ > 01:30PM Woah 30min
105
+ > 02:00PM Sit Down and Write 30min
106
+ > 02:30PM Programming in the Boondocks of Seattle 30min
107
+ > 03:00PM Ruby vs. Clojure for Back-End Development 30min
108
+ > 03:30PM A World Without HackerNews 30min
109
+ > 04:00PM Rails for Python Developers lightning
110
+ > 04:05PM Networking Event
111
+
112
+ ```
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:spec) do |t|
5
+ t.libs << "spec"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["spec/**/*_spec.rb"]
8
+ end
9
+
10
+ Rake::TestTask.new(:bench) do |t|
11
+ t.libs << "spec"
12
+ t.libs << "lib"
13
+ t.test_files = FileList["spec/**/*_bench.rb"]
14
+ end
15
+
16
+ task :default => :spec
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path("../../lib", __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require "conference_tracker"
7
+
8
+ input = ARGV.fetch(0, "")
9
+ ConferenceTracker::CLI.new(input).call
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "conference_tracker"
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(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "conference_tracker/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "conference_tracker"
8
+ s.version = ConferenceTracker::VERSION
9
+ s.authors = ["costajob"]
10
+ s.email = ["costajob@gmail.com"]
11
+ s.summary = "Implementation of the Conference Track Management kata"
12
+ s.homepage = "https://bitbucket.org/costajob/conference_tracker"
13
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
14
+ s.bindir = "bin"
15
+ s.executables << "conference_tracker"
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_development_dependency "bundler", "~> 1.15"
19
+ s.add_development_dependency "rake", "~> 10.0"
20
+ s.add_development_dependency "minitest", "~> 5.0"
21
+ s.add_development_dependency "benchmark-ips", "~> 2"
22
+ end
@@ -0,0 +1,43 @@
1
+ require "conference_tracker/scheduler"
2
+
3
+ module ConferenceTracker
4
+ class CLI
5
+ HELP_FLAGS = %w[-h --help]
6
+ COL_WIDTH = 23
7
+
8
+ def initialize(input,
9
+ pipe = STDOUT,
10
+ scheduler = Scheduler)
11
+ @input = input
12
+ @pipe = pipe
13
+ @scheduler = scheduler
14
+ end
15
+
16
+ def call
17
+ @pipe.puts output
18
+ end
19
+
20
+ private def output
21
+ return help if help?
22
+ return unless file?
23
+ talks = File.readlines(@input).map(&:strip)
24
+ @scheduler.new(talks).call
25
+ end
26
+
27
+ private def file?
28
+ File.file?(File.expand_path(@input))
29
+ end
30
+
31
+ private def help?
32
+ HELP_FLAGS.include?(@input)
33
+ end
34
+
35
+ private def help
36
+ [].tap do |h|
37
+ h << %q{Usage: conference_tracker ~/talks.txt}
38
+ h << " %-#{COL_WIDTH}s Print this help" % "-h --help"
39
+ h << " %-#{COL_WIDTH}s Load conference talks" % "<path-to-file>"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,20 @@
1
+ module ConferenceTracker
2
+ class Duration
3
+ SECS_IN_MIN = 60
4
+ UNITS = {
5
+ "lightning" => 5
6
+ }
7
+
8
+ def initialize(value)
9
+ @value = UNITS.fetch(value, value).to_i
10
+ end
11
+
12
+ def to_i
13
+ @value * SECS_IN_MIN
14
+ end
15
+
16
+ def to_s
17
+ UNITS.invert.fetch(@value, "#{@value}min")
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ module ConferenceTracker
2
+ class Event
3
+ NETWORKING = "Networking Event"
4
+
5
+ class Constraint
6
+ attr_reader :early_start
7
+
8
+ def initialize(early_start)
9
+ @early_start = Time.parse(early_start)
10
+ end
11
+
12
+ def valid?(time)
13
+ time >= @early_start
14
+ end
15
+ end
16
+
17
+ def self.lunch
18
+ new("Lunch", "12PM")
19
+ end
20
+
21
+ def self.networking
22
+ new("Networking Event", "4PM", Constraint.new("4PM"))
23
+ end
24
+
25
+ def initialize(name, start, constraint = nil)
26
+ @name = name
27
+ @start = ConferenceTracker.parse(start)
28
+ @constraint = constraint
29
+ end
30
+
31
+ def to_s
32
+ "#{early_start.strftime(FORMAT)} #{@name}"
33
+ end
34
+
35
+ def update(start)
36
+ @start = ConferenceTracker.parse(start)
37
+ self
38
+ end
39
+
40
+ private def early_start
41
+ return @start if @constraint.nil? || @constraint.valid?(@start)
42
+ @constraint.early_start
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ require "conference_tracker/talk"
2
+ require "conference_tracker/track"
3
+
4
+ module ConferenceTracker
5
+ class Scheduler
6
+ TRACK = "Track"
7
+
8
+ def initialize(talks, talk = Talk, track = Track)
9
+ @talks = talk.bulk(talks.to_a).sort { |a,b| b.to_i <=> a.to_i }
10
+ @track = track
11
+ end
12
+
13
+ def call
14
+ collect.to_a.reject(&:empty?).each_with_index.map do |track, i|
15
+ track.name = "#{TRACK} #{i+1}:"
16
+ track.schedule << ""
17
+ end
18
+ end
19
+
20
+ private def collect
21
+ return if @talks.empty?
22
+ @talks.reduce([]) do |tracks, talk|
23
+ tracks.each { |track| track.add(talk) }
24
+ tracks << @track.new.add(talk) unless talk.scheduled?
25
+ tracks
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,47 @@
1
+ require "forwardable"
2
+
3
+ module ConferenceTracker
4
+ class Session
5
+ extend Forwardable
6
+
7
+ def self.morning
8
+ new("9am", "12pm")
9
+ end
10
+
11
+ def self.afternoon
12
+ new("1pm", "5pm")
13
+ end
14
+
15
+ def_delegators :@talks, :size, :empty?
16
+
17
+ attr_reader :next_start
18
+
19
+ def initialize(start, finish)
20
+ @start = ConferenceTracker.parse(start)
21
+ @finish = ConferenceTracker.parse(finish)
22
+ @lapse = @finish - @start
23
+ @talks = []
24
+ end
25
+
26
+ def schedule
27
+ @talks.map(&:to_s)
28
+ end
29
+
30
+ def add(talk)
31
+ return if talk.scheduled? || overflow?(talk)
32
+ @talks << talk.schedule(next_start)
33
+ end
34
+
35
+ def next_start
36
+ @start + length
37
+ end
38
+
39
+ private def overflow?(talk)
40
+ length + talk.to_i > @lapse
41
+ end
42
+
43
+ private def length
44
+ @talks.reduce(0) { |length, talk| length += talk.to_i }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,43 @@
1
+ require "conference_tracker/duration"
2
+
3
+ module ConferenceTracker
4
+ class Talk
5
+ RULE = /(.*) (\d+min|#{Duration::UNITS.keys.join("|")})/
6
+
7
+ def self.factory(talk)
8
+ matching = talk.match(RULE)
9
+ return unless matching
10
+ new(*matching.captures)
11
+ end
12
+
13
+ def self.bulk(talks)
14
+ talks.map { |talk| factory(talk) }.compact
15
+ end
16
+
17
+ def initialize(name, duration)
18
+ @name = name
19
+ @duration = Duration.new(duration)
20
+ end
21
+
22
+ def to_s
23
+ [].tap do |s|
24
+ s << @start.strftime(FORMAT) if @start
25
+ s << @name
26
+ s << @duration
27
+ end.compact.join(" ")
28
+ end
29
+
30
+ def to_i
31
+ @duration.to_i
32
+ end
33
+
34
+ def schedule(time)
35
+ @start = ConferenceTracker.parse(time)
36
+ self
37
+ end
38
+
39
+ def scheduled?
40
+ !!@start
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ require "conference_tracker/event"
2
+ require "conference_tracker/session"
3
+
4
+ module ConferenceTracker
5
+ class Track
6
+ attr_accessor :name
7
+ attr_reader :morning, :afternoon
8
+
9
+ def initialize(morning = Session.morning, afternoon = Session.afternoon, event = Event)
10
+ @morning = morning
11
+ @afternoon = afternoon
12
+ @event = event
13
+ end
14
+
15
+ def add(talk)
16
+ @morning.add(talk) || @afternoon.add(talk)
17
+ self
18
+ end
19
+
20
+ def empty?
21
+ @morning.empty?
22
+ end
23
+
24
+ def schedule
25
+ [].tap do |s|
26
+ s << @name
27
+ s.concat(@morning.schedule)
28
+ s << @event.lunch.to_s
29
+ s.concat(@afternoon.schedule)
30
+ s << @event.networking.update(@afternoon.next_start).to_s
31
+ end.compact
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module ConferenceTracker
2
+ VERSION = "1.1.0"
3
+ end
@@ -0,0 +1,18 @@
1
+ require "time"
2
+ require "conference_tracker/cli"
3
+ require "conference_tracker/version"
4
+
5
+ module ConferenceTracker
6
+ extend self
7
+
8
+ FORMAT = "%I:%M%p"
9
+
10
+ def call(talks)
11
+ Scheduler.new(talks).call
12
+ end
13
+
14
+ def parse(time)
15
+ return time if time.instance_of?(Time)
16
+ Time.parse(time)
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: conference_tracker
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - costajob
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: benchmark-ips
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2'
69
+ description:
70
+ email:
71
+ - costajob@gmail.com
72
+ executables:
73
+ - conference_tracker
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - README.md
80
+ - Rakefile
81
+ - bin/conference_tracker
82
+ - bin/console
83
+ - bin/setup
84
+ - conference_tracker.gemspec
85
+ - lib/conference_tracker.rb
86
+ - lib/conference_tracker/cli.rb
87
+ - lib/conference_tracker/duration.rb
88
+ - lib/conference_tracker/event.rb
89
+ - lib/conference_tracker/scheduler.rb
90
+ - lib/conference_tracker/session.rb
91
+ - lib/conference_tracker/talk.rb
92
+ - lib/conference_tracker/track.rb
93
+ - lib/conference_tracker/version.rb
94
+ homepage: https://bitbucket.org/costajob/conference_tracker
95
+ licenses: []
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.6.11
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Implementation of the Conference Track Management kata
117
+ test_files: []