words_counted 0.0.1

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: 9834aaae70272cc358a8bd7f846b56077c94c322
4
+ data.tar.gz: 80a6bd1a780307da11adc85a267ae8ad77b60be3
5
+ SHA512:
6
+ metadata.gz: e0089b2b4ef682901c65c01641fb6643e7d85c3bf13b2b14dbb1a6d99b4ddaf1c5c74f8e40c7fd1a3ba3af8d4229cec229df98c826499d690b8a7db012279fd9
7
+ data.tar.gz: 227c554bdd420091afdd134a753563d7cf4ec1443e8bfeea2dc22c214df098da2f9dceee4f6fe5101c2258859ddc95a3c80898e2f5d0d75d3e5baaf0dfaf7e33
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in words_counted.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Mohamad El-Husseini
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # Words Counted
2
+
3
+ This Ruby gem is a word counter that includes some handy utility methods.
4
+
5
+ ### Features
6
+
7
+ 1. Count the number of words in a string.
8
+ 2. Get a hash of each word and the number of times it occurres.
9
+ 3. Get a hash of each word and its length.
10
+ 4. Get the most occurring word(s) and its number of occurrences.
11
+ 5. Get the longest word(s) and its length.
12
+ 6. Ability to filter words.
13
+ 7. Filters special characters but respects hyphens and apostrophes.
14
+
15
+ See usage instructions for details on each feature.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ gem 'words_counted'
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install words_counted
30
+
31
+ ## Usage
32
+
33
+ Create an instance of `Counter` and pass in a string and an optional filter.
34
+
35
+ ```ruby
36
+ counter = WordsCounted::Counter.new(
37
+ "We are all in the gutter, but some of us are looking at the stars."
38
+ )
39
+ ```
40
+
41
+ ### `.word_count`
42
+
43
+ Returns the word count of a given string. The word count includes only alpha characters. Hyphenated and words with apostrophes are considered a single word.
44
+
45
+ ```ruby
46
+ counter.word_count #=> 15
47
+ ```
48
+ ### `.word_occurrences`
49
+
50
+ Returns a hash of words and their number of occurrences. Uppercase and lowercase words are counted as the same word.
51
+
52
+ ```ruby
53
+ counter.word_occurrences #=> { "we"=>1, "are"=>2, "all"=>1, "in"=>1, "the"=>2, "gutter"=>1, "but"=>1, "some"=>1, "of"=>1, "us"=>1, "looking"=>1, "at"=>1, "stars"=>1}
54
+ ```
55
+
56
+ ### `.most_occurring_words`
57
+
58
+ Returns a two dimensional array of the highest occurring word and its number of occurrences. In case there is a tie all tied words are returned.
59
+
60
+ ```ruby
61
+ counter.most_occurring_words #=> [["are", 2], ["the", 2]]
62
+ ```
63
+
64
+ ### `.word_lengths`
65
+
66
+ Returns a hash of words and their lengths.
67
+
68
+ ```ruby
69
+ counter.word_lengths #=> {"We"=>2, "are"=>3, "all"=>3, "in"=>2, "the"=>3, "gutter"=>6, "but"=>3, "some"=>4, "of"=>2, "us"=>2, "looking"=>7, "at"=>2, "stars"=>5}
70
+ ```
71
+
72
+ ### `.longest_word`
73
+
74
+ Returns a two dimensional array of the longest word and its length. In case there is a tie all tied words are returned.
75
+
76
+ ## Filtering
77
+
78
+ You can pass in a space-delimited word list to filter words that you don't want to count. Filter words should be lowercase. The filter will remove both uppercase and lowercase variants of the word.
79
+
80
+ ```ruby
81
+ WordsCounted::Counter.new("That was magnificent, Trevor.", "that was")
82
+ #=> <WordsCounted::Counter:0x007fd494312520 @words=["magnificent", "Trevor"]>
83
+ ```
84
+
85
+ ## About
86
+
87
+ Originally I wrote this program for a code challenge. My initial implementation was decent, but it could have been better. Thanks to [Dave Yarwood](http://codereview.stackexchange.com/a/47515/1563) for helping me improve my code. Some of this code is based on his recommendations. You can find the original implementation as well as the code review on [Code Review](http://codereview.stackexchange.com/questions/46105/a-ruby-string-analyser).
88
+
89
+ ## Contributing
90
+
91
+ 1. Fork it
92
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
93
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
94
+ 4. Push to the branch (`git push origin my-new-feature`)
95
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
7
+
8
+ task :console do
9
+ exec "irb -r words_counted -I ./lib"
10
+ end
@@ -0,0 +1,37 @@
1
+ module WordsCounted
2
+ class Counter
3
+ attr_reader :words
4
+
5
+ WORD_REGEX = /[^\p{Alpha}\-']+/
6
+
7
+ def initialize(string, filter = "")
8
+ @words = string.split(WORD_REGEX).reject { |word| filter.split.include? word.downcase }
9
+ end
10
+
11
+ def word_count
12
+ words.size
13
+ end
14
+
15
+ def word_occurrences
16
+ @occurrences ||= words.each_with_object(Hash.new(0)) { |word, result| result[word.downcase] += 1 }
17
+ end
18
+
19
+ def word_lengths
20
+ @lengths ||= words.each_with_object({}) { |word, result| result[word] ||= word.length }
21
+ end
22
+
23
+ def most_occurring_words
24
+ highest_ranking word_occurrences
25
+ end
26
+
27
+ def longest_words
28
+ highest_ranking word_lengths
29
+ end
30
+
31
+ private
32
+
33
+ def highest_ranking(entries)
34
+ entries.group_by { |word, occurrence| occurrence }.sort.last.last
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module WordsCounted
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,10 @@
1
+ require "words_counted/version"
2
+ require "words_counted/counter"
3
+
4
+ begin
5
+ require "pry"
6
+ rescue LoadError
7
+ end
8
+
9
+ module WordsCounted
10
+ end
@@ -0,0 +1,84 @@
1
+ require 'words_counted'
2
+
3
+ # This file was generated by the `rspec --init` command. Conventionally, all
4
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
5
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
6
+ # file to always be loaded, without a need to explicitly require it in any files.
7
+ #
8
+ # Given that it is always loaded, you are encouraged to keep this file as
9
+ # light-weight as possible. Requiring heavyweight dependencies from this file
10
+ # (such as loading up an entire rails app) will add to the boot time of your
11
+ # test suite on EVERY test run, even for an individual file that may not need
12
+ # all of that loaded.
13
+ #
14
+ # The `.rspec` file also contains a few flags that are not defaults but that
15
+ # users commonly want.
16
+ #
17
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
18
+ RSpec.configure do |config|
19
+ # The settings below are suggested to provide a good initial experience
20
+ # with RSpec, but feel free to customize to your heart's content.
21
+ =begin
22
+ # These two settings work together to allow you to limit a spec run
23
+ # to individual examples or groups you care about by tagging them with
24
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
25
+ # get run.
26
+ config.filter_run :focus
27
+ config.run_all_when_everything_filtered = true
28
+
29
+ # Many RSpec users commonly either run the entire suite or an individual
30
+ # file, and it's useful to allow more verbose output when running an
31
+ # individual spec file.
32
+ if config.files_to_run.one?
33
+ # RSpec filters the backtrace by default so as not to be so noisy.
34
+ # This causes the full backtrace to be printed when running a single
35
+ # spec file (e.g. to troubleshoot a particular spec failure).
36
+ config.full_backtrace = true
37
+
38
+ # Use the documentation formatter for detailed output,
39
+ # unless a formatter has already been configured
40
+ # (e.g. via a command-line flag).
41
+ config.formatter = 'doc' if config.formatters.none?
42
+ end
43
+
44
+ # Print the 10 slowest examples and example groups at the
45
+ # end of the spec run, to help surface which specs are running
46
+ # particularly slow.
47
+ config.profile_examples = 10
48
+
49
+ # Run specs in random order to surface order dependencies. If you find an
50
+ # order dependency and want to debug it, you can fix the order by providing
51
+ # the seed, which is printed after each run.
52
+ # --seed 1234
53
+ config.order = :random
54
+
55
+ # Seed global randomization in this process using the `--seed` CLI option.
56
+ # Setting this allows you to use `--seed` to deterministically reproduce
57
+ # test failures related to randomization by passing the same `--seed` value
58
+ # as the one that triggered the failure.
59
+ Kernel.srand config.seed
60
+
61
+ # rspec-expectations config goes here. You can use an alternate
62
+ # assertion/expectation library such as wrong or the stdlib/minitest
63
+ # assertions if you prefer.
64
+ config.expect_with :rspec do |expectations|
65
+ # Enable only the newer, non-monkey-patching expect syntax.
66
+ # For more details, see:
67
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
68
+ expectations.syntax = :expect
69
+ end
70
+
71
+ # rspec-mocks config goes here. You can use an alternate test double
72
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
73
+ config.mock_with :rspec do |mocks|
74
+ # Enable only the newer, non-monkey-patching expect syntax.
75
+ # For more details, see:
76
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
77
+ mocks.syntax = :expect
78
+
79
+ # Prevents you from mocking or stubbing a method that does not exist on
80
+ # a real object. This is generally recommended.
81
+ mocks.verify_partial_doubles = true
82
+ end
83
+ =end
84
+ end
@@ -0,0 +1,94 @@
1
+ require "spec_helper"
2
+
3
+ module WordsCounted
4
+ describe Counter do
5
+
6
+ describe ".words" do
7
+ let(:counter) { Counter.new("We are all in the gutter, but some of us are looking at the stars.") }
8
+
9
+ it "returns an array" do
10
+ expect(counter.words).to be_a(Array)
11
+ end
12
+
13
+ it "splits words" do
14
+ expect(counter.words).to eq(%w[We are all in the gutter but some of us are looking at the stars])
15
+ end
16
+
17
+ it "removes special characters" do
18
+ counter = Counter.new("Hello! # $ % 12345 * & % How do you do?")
19
+ expect(counter.words).to eq(%w[Hello How do you do])
20
+ end
21
+
22
+ it "counts hyphenated words as one" do
23
+ counter = Counter.new("I am twenty-two.")
24
+ expect(counter.words).to eq(%w[I am twenty-two])
25
+ end
26
+
27
+ it "does not split words on apostrophe" do
28
+ counter = Counter.new("Bust 'em! Them be Jim's bastards'.")
29
+ expect(counter.words).to eq(%w[Bust 'em Them be Jim's bastards'])
30
+ end
31
+
32
+ it "filters words" do
33
+ counter = Counter.new("That was magnificent, Trevor.", "magnificent")
34
+ expect(counter.words).to eq(%w[That was Trevor])
35
+ end
36
+ end
37
+
38
+ describe ".word_count" do
39
+ let(:counter) { Counter.new("In that case I'll take measures to secure you, woman!") }
40
+
41
+ it "returns the correct word count" do
42
+ expect(counter.word_count).to eq(10)
43
+ end
44
+ end
45
+
46
+ describe ".word_occurrences" do
47
+ let(:counter) { Counter.new("Bad, bad, piggy!") }
48
+
49
+ it "returns a hash" do
50
+ expect(counter.word_occurrences).to be_a(Hash)
51
+ end
52
+
53
+ it "treats capitalized words as the same word" do
54
+ expect(counter.word_occurrences).to eq({ "bad" => 2, "piggy" => 1 })
55
+ end
56
+ end
57
+
58
+ describe ".most_occurring_words" do
59
+ let(:counter) { Counter.new("One should always be in love. That is the reason one should never marry.") }
60
+
61
+ it "returns an array" do
62
+ expect(counter.most_occurring_words).to be_a(Array)
63
+ end
64
+
65
+ it "returns highest occuring words" do
66
+ expect(counter.most_occurring_words).to eq([["one", 2],["should", 2]])
67
+ end
68
+ end
69
+
70
+ describe '.word_lengths' do
71
+ let(:counter) { Counter.new("One two three.") }
72
+
73
+ it "returns a hash" do
74
+ expect(counter.word_lengths).to be_a(Hash)
75
+ end
76
+
77
+ it "returns a hash of word lengths" do
78
+ expect(counter.word_lengths).to eq({ "One" => 3, "two" => 3, "three" => 5 })
79
+ end
80
+ end
81
+
82
+ describe ".longest_words" do
83
+ let(:counter) { Counter.new("Those whom the gods love grow young.") }
84
+
85
+ it "returns an array" do
86
+ expect(counter.longest_words).to be_a(Array)
87
+ end
88
+
89
+ it "returns the longest words" do
90
+ expect(counter.longest_words).to eq([["Those", 5],["young", 5]])
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'words_counted/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "words_counted"
8
+ spec.version = WordsCounted::VERSION
9
+ spec.authors = ["Mohamad El-Husseini"]
10
+ spec.email = ["husseini.mel@gmail.com"]
11
+ spec.description = %q{A Ruby word counter with helpful utility methods.}
12
+ spec.summary = %q{See README.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "pry"
25
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: words_counted
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mohamad El-Husseini
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-30 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.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A Ruby word counter with helpful utility methods.
70
+ email:
71
+ - husseini.mel@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - .rspec
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - lib/words_counted.rb
83
+ - lib/words_counted/counter.rb
84
+ - lib/words_counted/version.rb
85
+ - spec/spec_helper.rb
86
+ - spec/words_counted/counter_spec.rb
87
+ - words_counted.gemspec
88
+ homepage: ''
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.0.6
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: See README.
112
+ test_files:
113
+ - spec/spec_helper.rb
114
+ - spec/words_counted/counter_spec.rb