-
-
Notifications
You must be signed in to change notification settings - Fork 50
Macbeth Analyzer Solution #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| .idea |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| source 'https://rubygems.org' | ||
|
|
||
| gem 'nokogiri', '~> 1.6.0' | ||
|
|
||
| group :development, :test do | ||
| gem "minitest", "~> 5.0.7" | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| GEM | ||
| remote: https://rubygems.org/ | ||
| specs: | ||
| mini_portile (0.5.0) | ||
| minitest (5.0.7) | ||
| nokogiri (1.6.0) | ||
| mini_portile (~> 0.5.0) | ||
|
|
||
| PLATFORMS | ||
| ruby | ||
|
|
||
| DEPENDENCIES | ||
| minitest (~> 5.0.7) | ||
| nokogiri (~> 1.6.0) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,33 +1,6 @@ | ||
| ***An exercise for Prime subscribers. Visit http://learn.thoughtbot.com/prime to learn more.*** | ||
|
|
||
| ### Difficulty level: intermediate. | ||
| <h2>Run</h2> | ||
| ruby macbeth_analyzer.rb | ||
| <h2>Run Tests</h2> | ||
| ruby macbeth_analyzer_spec.rb | ||
|
|
||
| ## Your Task | ||
|
|
||
| As a Shakespeare buff, statistics junkie, and unix lover, Ben finds himself wanting a command-line tool for analyzing Macbeth. | ||
|
|
||
| Write a command-line program that prints the number of lines spoken by each character in the play. | ||
|
|
||
| Sample usage/output (using made-up numbers): | ||
|
|
||
| $ ruby macbeth_analyzer.rb | ||
| 543 Macbeth | ||
| 345 Banquo | ||
| 220 Duncan | ||
| (etc.) | ||
|
|
||
| You can find an XML-encoded version of Macbeth here: http://www.ibiblio.org/xml/examples/shakespeare/macbeth.xml. Your program should download and parse this file at runtime. | ||
|
|
||
| Your solution must be tested, preferably via TDD. | ||
|
|
||
| ## Working/Submitting | ||
|
|
||
| 1. To work on this exercise, fork the repo and begin implementing your solution. | ||
| 2. When you are done, copy the output of your program into a file in this repository. | ||
| 3. Create a pull request so your code can be reviewed. | ||
| 4. Perform a code review on at least one other person's solution. Your comments should follow our code review guidelines: https://github.com/thoughtbot/guides/tree/master/code-review. Most important: be friendly. Make suggestions, not demands. | ||
| 5. Improve your solution based on the comments you've received and approaches you've learned from reviewing others' attempts. | ||
|
|
||
| ## Bounty | ||
|
|
||
| While knowledge and skill improvement are their own rewards, the author with the best solution (as judged by thoughtbot) will receive a cool thoughtbot t-shirt. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
|
|
||
| class MacbethAnalyzer | ||
| require 'net/http' | ||
| require 'open-uri' | ||
| require 'nokogiri' | ||
|
|
||
| def run | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice high level of abstraction here. |
||
| line_counts = parse_counts(load_file) | ||
| display(line_counts) | ||
| end | ||
|
|
||
| def load_file | ||
| Nokogiri::HTML(open('http://www.ibiblio.org/xml/examples/shakespeare/macbeth.xml')) | ||
| end | ||
|
|
||
| def parse_counts(xml_doc) | ||
| line_count = Hash.new(0) | ||
| speeches = xml_doc.css('speech') | ||
| speeches.each do |speech| | ||
| speaker = speech.css('speaker').text | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are some speech tags that have more than 1 speaker. I made this mistake initially too. :)
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you provide an example? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line number: 1738 of macbeth.xml
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ugh. we need a DTD for this file to fail against ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here you go: www.ibiblio.org/xml/examples/shakespeare/play.dtd There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, I missed this too |
||
| count = speech.css('line').count | ||
| line_count[speaker] += count if speaker != 'ALL' | ||
| end | ||
| line_count | ||
| end | ||
|
|
||
| def display(line_counts) | ||
| line_counts.sort_by{|_key, value| value}.reverse.each do |v| | ||
| puts "#{v[1]} #{v[0]}" | ||
| end | ||
| end | ||
| end | ||
|
|
||
| #MacbethAnalyzer.new.run | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
|
|
||
| require_relative 'lib/macbeth_analyzer' | ||
| MacbethAnalyzer.new.run |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| require 'minitest' | ||
| require 'minitest/autorun' | ||
| require_relative 'lib/macbeth_analyzer' | ||
|
|
||
| class TestMacbethAnalyzer < MiniTest::Test | ||
|
|
||
| describe '#load_file' do | ||
| def setup | ||
| @ma = MacbethAnalyzer.new | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not know minitest but is there a way to declare this once, before all the tests, so you don't have to declare it 3 times? |
||
| end | ||
| def test_load_file | ||
| xml_doc = @ma.load_file | ||
| refute_nil(xml_doc) | ||
| end | ||
| def test_load_file_2 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I bet you can come up with a better name than this. :) |
||
| xml_doc = @ma.load_file | ||
| assert xml_doc.instance_of?(Nokogiri::HTML::Document), "Expected #{xml_doc.inspect} to be an instance of #{Nokogiri::HTML::Document}, not #{xml_doc.class}" | ||
| end | ||
| end | ||
|
|
||
| describe "#parse_counts" do | ||
| def setup | ||
| @ma = MacbethAnalyzer.new | ||
| end | ||
| def test_parse_returns_one_speaker | ||
| line_count = @ma.parse_counts(Nokogiri::XML("<scene><speech><speaker>A</speaker><line>B</line></speech></scene>")) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A multiline string would probably be more readable here, e.g. by using |
||
| assert_equal( line_count.count, 1 ) | ||
| end | ||
| def test_parse_returns_one_speaker_one_line | ||
| line_count = @ma.parse_counts(Nokogiri::XML("<scene><speech><speaker>A</speaker><line>B</line></speech></scene>")) | ||
| assert_equal( line_count["A"], 1 ) | ||
| end | ||
| def test_parse_returns_one_speaker_two_lines | ||
| line_count = @ma.parse_counts(Nokogiri::XML("<scene><speech><speaker>A</speaker><line>B</line><line>C</line></speech></scene>")) | ||
| assert_equal( line_count["A"], 2 ) | ||
| end | ||
| def test_parse_returns_two_speakers | ||
| line_count = @ma.parse_counts(Nokogiri::XML("<scene><speech><speaker>A</speaker><line>B</line></speech><speech><speaker>C</speaker><line>D</line></speech></scene>")) | ||
| assert_equal( line_count.count, 2 ) | ||
| end | ||
| end | ||
|
|
||
| describe "#display" do | ||
| def setup | ||
| @ma = MacbethAnalyzer.new | ||
| end | ||
| def test_display | ||
| output = capture_io do | ||
| @ma.display({'A' => 1}) | ||
| end | ||
| assert_equal ["1 A\n",""], output | ||
| end | ||
| def test_display_sort | ||
| output = capture_io do | ||
| @ma.display({'A' => 1, 'B' => 2}) | ||
| end | ||
| assert_equal ["2 B\n1 A\n", ""], output | ||
| end | ||
| end | ||
| end | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| 718 MACBETH | ||
| 265 LADY MACBETH | ||
| 212 MALCOLM | ||
| 180 MACDUFF | ||
| 135 ROSS | ||
| 113 BANQUO | ||
| 73 LENNOX | ||
| 70 DUNCAN | ||
| 62 First Witch | ||
| 46 Porter | ||
| 45 Doctor | ||
| 41 LADY MACDUFF | ||
| 39 HECATE | ||
| 35 Sergeant | ||
| 30 First Murderer | ||
| 30 SIWARD | ||
| 27 Third Witch | ||
| 27 Second Witch | ||
| 23 Gentlewoman | ||
| 23 Messenger | ||
| 21 Lord | ||
| 21 ANGUS | ||
| 20 Son | ||
| 15 Second Murderer | ||
| 12 MENTEITH | ||
| 11 Old Man | ||
| 11 CAITHNESS | ||
| 10 DONALBAIN | ||
| 8 Third Murderer | ||
| 7 YOUNG SIWARD | ||
| 5 Third Apparition | ||
| 5 Servant | ||
| 5 SEYTON | ||
| 4 Second Apparition | ||
| 3 Lords | ||
| 2 First Apparition | ||
| 2 Both Murderers | ||
| 2 FLEANCE | ||
| 1 ATTENDANT | ||
| 1 MACBETHLENNOX | ||
| 1 Soldiers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job including usage instructions!