urban_dictionary 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MmQ5NjJjOTM5OTBmYWRkMjI0Nzc5ODE5ZGNlZGZiYTljZTNmZjFjZA==
5
- data.tar.gz: !binary |-
6
- MzQxMDhhNDMxZmNlM2U1ZWUyNjI4OGNmMWEwMjkwOWRlYzQxMjhhZg==
2
+ SHA1:
3
+ metadata.gz: c4f3029bc9ff059717597149efd3464a53b7be3e
4
+ data.tar.gz: a4a4aaaedcd3b981d33ec34417c1026a20060a56
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NGRmMWY0Y2MwMWM2NWMyYmMwMjI3NTU2ZDcyNjJjOWJkNGI2NDFlZjNlOGVl
10
- MGI1ODIyZTAyN2FhODNkYjIyODhiNGQ5NWEzMmI0OTNlZGQ3Yzg4ZDA5Mzg2
11
- Y2M3ZjQ4ZDY2ZjZlNDhjNDE4NWEyOWI2YTU0MjI2OWJkMjI2M2Y=
12
- data.tar.gz: !binary |-
13
- MjZlMWZhMjA2OWMzY2NhZGI0YzFlZGRmNmIwNTA4YzNlZDQyNTFjMzAxODY0
14
- NmZiNmJkOWU5MWI0ZDgxNjFmNTQxNzFiYTRjMTM1NDQzZTg5MTYyZDRhNzdl
15
- MWVjZTM5ZjVmMmM3NDExOGRmMGY3MzM5ZjRkOTA2YjBhYTZhNmQ=
6
+ metadata.gz: ec7e8f36aa8631ba8cb6a5db07b4743a1353841d3d25539e3bb9af71a7605765275c2e56d8e66a53dccb66c35a286e04ff990eba99e2f514f29c8448ae9b4117
7
+ data.tar.gz: a37a3c5ea34dd959a66cc7cf977a46a86c7ae46ff7f76c70c5c3397358043d262cc9f0cd2c42000b03aa2736d4c0b5d790d13084a1f05cbf074536c186af5c96
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0 - 2016-03-01
4
+ - Added support for `-n <number>` or `--definitions=<number>` to limit output
5
+ - Fixed output mangled by carriage returns (`\r`)
6
+ - Added `--format=definition` that only outputs the definitions for a word
7
+
3
8
  ## 1.0.0 - 2016-02-15
4
9
  - Fixed broken parsing of Urban Dictionary's new layout
5
10
  - Fixed bug where undefined words are displayed as the shrug emoticon (`¯\_(ツ)_/¯`)
data/README.md CHANGED
@@ -45,7 +45,7 @@ Specify the output format with `--format`. The default is `plain`; `json` is als
45
45
  "entries": [
46
46
  {
47
47
  "definition": "keepin it real to the fullest and super tight.",
48
- "example": "end of the convo\rLuke: aight man, peace\rQ: kool homie, keep it one hundred (100)"
48
+ "example": "end of the convo\nLuke: aight man, peace\nQ: kool homie, keep it one hundred (100)"
49
49
  },
50
50
  ...
51
51
  }
@@ -26,5 +26,6 @@ module UrbanDictionary
26
26
  end
27
27
  end
28
28
 
29
+ UrbanDictionary::Formatter.register(:definition, UrbanDictionary::DefinitionFormatter)
29
30
  UrbanDictionary::Formatter.register(:json, UrbanDictionary::JsonFormatter)
30
31
  UrbanDictionary::Formatter.register(:plain, UrbanDictionary::PlainFormatter)
@@ -68,8 +68,16 @@ module UrbanDictionary
68
68
  options[:random] = r
69
69
  end
70
70
 
71
+ opts.on("-n", "--definitions=NUMBER", "Limit output to the first n definitions") do |n|
72
+ options[:limit] = begin
73
+ Integer(n)
74
+ rescue ArgumentError
75
+ raise OptionParser::InvalidArgument, "#{n} is not a valid number of definitions"
76
+ end
77
+ end
78
+
71
79
  options[:format] = DEFAULT_FORMAT
72
- opts.on("-f", "--format=FORMAT", "Output format (plain, json)") do |f|
80
+ opts.on("-f", "--format=FORMAT", "Output format (plain, json, definition)") do |f|
73
81
  format = f.downcase.to_sym
74
82
  unless UrbanDictionary::Formatter.registered.include?(format)
75
83
  raise OptionParser::InvalidOption, "#{f} is not a valid format"
@@ -79,8 +87,17 @@ module UrbanDictionary
79
87
  end
80
88
  end
81
89
 
90
+ def parse
91
+ begin
92
+ options[:remaining] = option_parser.parse(@args)
93
+ rescue OptionParser::InvalidOption, OptionParser::InvalidArgument => e
94
+ @stderr.puts e.message
95
+ exit(1)
96
+ end
97
+ end
98
+
82
99
  def run
83
- options[:remaining] = option_parser.parse(@args)
100
+ parse
84
101
 
85
102
  if options[:remaining].empty? && !options[:random]
86
103
  @stdout.puts option_parser.help
@@ -99,6 +116,10 @@ module UrbanDictionary
99
116
  exit(1)
100
117
  end
101
118
 
119
+ if options[:limit]
120
+ word = UrbanDictionary::Word.new(word.word, word.entries.first(options[:limit]))
121
+ end
122
+
102
123
  formatter = UrbanDictionary::Formatter.for(options[:format])
103
124
  @stdout.puts(formatter.format(word))
104
125
  end
@@ -2,6 +2,15 @@ require 'multi_json'
2
2
 
3
3
  module UrbanDictionary
4
4
  class Formatter
5
+ class Util
6
+ PATTERN = Regexp.compile(/\r\n|\r|\n/)
7
+ NEW_LINE = "\n"
8
+
9
+ def self.convert_linebreaks(str)
10
+ str.gsub(PATTERN, NEW_LINE)
11
+ end
12
+ end
13
+
5
14
  def self.register(name, klass)
6
15
  @formatters ||= {}
7
16
  if @formatters.include?(name)
@@ -31,9 +40,9 @@ module UrbanDictionary
31
40
  output << '-' * word.size
32
41
  output << ''
33
42
  word.entries.each_with_index do |entry, i|
34
- output << "#{i + 1}. #{entry.definition}"
43
+ output << "#{i + 1}. #{Util.convert_linebreaks(entry.definition)}"
35
44
  output << ""
36
- output << "Example: #{entry.example}"
45
+ output << "Example: #{Util.convert_linebreaks(entry.example)}"
37
46
  output << ""
38
47
  output << ""
39
48
  end
@@ -41,14 +50,20 @@ module UrbanDictionary
41
50
  end
42
51
  end
43
52
 
53
+ class DefinitionFormatter < Formatter
54
+ def self.format(word)
55
+ word.entries.map {|ea| Util.convert_linebreaks(ea.definition) }.join("\n")
56
+ end
57
+ end
58
+
44
59
  class JsonFormatter < Formatter
45
60
  def self.format(word)
46
61
  hsh = {
47
62
  :word => word.word,
48
63
  :entries => word.entries.map do |entry|
49
64
  {
50
- :definition => entry.definition,
51
- :example => entry.example
65
+ :definition => Util.convert_linebreaks(entry.definition),
66
+ :example => Util.convert_linebreaks(entry.example)
52
67
  }
53
68
  end
54
69
  }
@@ -1,3 +1,3 @@
1
1
  module UrbanDictionary
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -5,26 +5,23 @@ require 'shellwords'
5
5
  require 'stringio'
6
6
  require 'webmock/rspec'
7
7
 
8
- RSpec.configure do |config|
9
- config.run_all_when_everything_filtered = true
10
- config.filter_run :focus
11
- config.order = 'random'
12
- end
13
-
14
- module Test
15
- def self.load_fixture(name)
16
- File.read(File.expand_path("../html/#{name}", __FILE__))
17
- end
18
-
8
+ module TestHelpers
19
9
  class IO < StringIO
20
10
  def content
21
11
  rewind
22
12
  read
23
13
  end
14
+ end
24
15
 
25
- def include?(str)
26
- content.include?(str)
27
- end
16
+ def load_fixture(name)
17
+ File.read(File.expand_path("../html/#{name}", __FILE__))
18
+ end
19
+
20
+ def mk_word(term, definitions, examples)
21
+ UrbanDictionary::Word.new(
22
+ term,
23
+ Array(definitions).zip(Array(examples)).map {|ea| UrbanDictionary::Entry.new(*ea) }
24
+ )
28
25
  end
29
26
  end
30
27
 
@@ -35,3 +32,9 @@ class String
35
32
  end
36
33
  end
37
34
 
35
+ RSpec.configure do |config|
36
+ config.run_all_when_everything_filtered = true
37
+ config.filter_run :focus
38
+ config.order = 'random'
39
+ config.include TestHelpers
40
+ end
@@ -15,33 +15,32 @@ describe UrbanDictionary::CLI do
15
15
  def mk_cli(str, dictionary = nil)
16
16
  config = CLI::Config.new(
17
17
  :args => str.to_argv,
18
- :stdout => Test::IO.new,
19
- :stderr => Test::IO.new,
18
+ :stdout => TestHelpers::IO.new,
19
+ :stderr => TestHelpers::IO.new,
20
20
  )
21
21
  config.update(:dictionary, dictionary) unless dictionary.nil?
22
22
  cli = CLI.new(config)
23
23
  [cli, config]
24
24
  end
25
25
 
26
- def mk_word(term, definitions, examples)
27
- UrbanDictionary::Word.new(
28
- term,
29
- Array(definitions).zip(Array(examples)).map {|ea| UrbanDictionary::Entry.new(*ea) }
30
- )
31
- end
32
-
33
26
  describe "#run" do
34
27
  it "outputs help when called with no arguments" do
35
28
  cli, config = mk_cli("")
36
29
  cli.run
37
- expect(config.stdout).to include("Usage: urban_dictionary")
30
+ expect(config.stdout.content).to include("Usage: urban_dictionary")
31
+ end
32
+
33
+ it "outputs an error message when an invalid option is provided" do
34
+ cli, config = mk_cli("--invalid-option")
35
+ suppress_exit(1) { cli.run }
36
+ expect(config.stderr.content).to include("invalid option: --invalid-option")
38
37
  end
39
38
 
40
39
  it "outputs error when word has no definition" do
41
40
  dictionary = double("dictionary", :define => nil)
42
41
  cli, config = mk_cli("undefined word", dictionary)
43
42
  suppress_exit(1) { cli.run }
44
- expect(config.stderr).to include("No definition found for 'undefined word'")
43
+ expect(config.stderr.content).to include("No definition found for 'undefined word'")
45
44
  end
46
45
 
47
46
  it "outputs a word's definition when found" do
@@ -49,7 +48,7 @@ describe UrbanDictionary::CLI do
49
48
  dictionary = double("dictionary", :define => word)
50
49
  cli, config = mk_cli(word.word, dictionary)
51
50
  cli.run
52
- expect(config.stdout).to include(word.word)
51
+ expect(config.stdout.content).to include(word.word)
53
52
  end
54
53
 
55
54
  it "outputs a random word when --random is provided" do
@@ -57,7 +56,7 @@ describe UrbanDictionary::CLI do
57
56
  dictionary = double("dictionary", :random_word => random_word)
58
57
  cli, config = mk_cli("--random", dictionary)
59
58
  cli.run
60
- expect(config.stdout).to include(random_word.word)
59
+ expect(config.stdout.content).to include(random_word.word)
61
60
  end
62
61
 
63
62
  it "accepts --format to specify output format" do
@@ -68,5 +67,15 @@ describe UrbanDictionary::CLI do
68
67
  obj = MultiJson.load(config.stdout.content)
69
68
  expect(obj).to include("word" => word.word)
70
69
  end
70
+
71
+ it "accepts -n to limit number of definitions" do
72
+ word = mk_word("complex word", ["def #1", "def #2", "def #3"], ["example #1", "example #2", "example #3"])
73
+ dictionary = double("dictionary", :define => word)
74
+ cli, config = mk_cli("-n 1 #{word.word}", dictionary)
75
+ cli.run
76
+ expect(config.stdout.content).to include("def #1")
77
+ expect(config.stdout.content).not_to include("def #2")
78
+ expect(config.stdout.content).not_to include("def #3")
79
+ end
71
80
  end
72
81
  end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ describe UrbanDictionary::PlainFormatter do
4
+ let(:formatter) { UrbanDictionary::PlainFormatter }
5
+
6
+ describe "#format" do
7
+ it "converts carriage returns to new lines" do
8
+ word = mk_word("term", "definition\rwith CR", "example\rwith CR")
9
+ output = formatter.format(word)
10
+ expect(output).to include("definition\nwith CR")
11
+ expect(output).to include("example\nwith CR")
12
+ end
13
+ end
14
+ end
15
+
16
+ describe UrbanDictionary::DefinitionFormatter do
17
+ let(:formatter) { UrbanDictionary::DefinitionFormatter }
18
+ let(:word) { mk_word("term", "definition", "example") }
19
+
20
+ describe "#format" do
21
+ it "includes the definition" do
22
+ output = formatter.format(word)
23
+ expect(output).to include(word.entries.first.definition)
24
+ end
25
+
26
+ it "does not include the word" do
27
+ output = formatter.format(word)
28
+ expect(output).not_to include(word.word)
29
+ end
30
+
31
+ it "does not include examples" do
32
+ output = formatter.format(word)
33
+ expect(output).not_to include(word.entries.first.example)
34
+ end
35
+ end
36
+ end
37
+
38
+
39
+ describe UrbanDictionary::JsonFormatter do
40
+ let(:formatter) { UrbanDictionary::JsonFormatter }
41
+
42
+ describe "#format" do
43
+ it "converts carriage returns to new lines" do
44
+ word = mk_word("term", "definition\rwith CR", "example\rwith CR")
45
+ output = MultiJson.load(formatter.format(word))
46
+ expected_output = [
47
+ {"definition" => "definition\nwith CR", "example" => "example\nwith CR"}
48
+ ]
49
+ expect(output["entries"]).to eq(expected_output)
50
+ end
51
+ end
52
+ end
@@ -24,8 +24,8 @@ describe UrbanDictionary::Word do
24
24
  describe "class method" do
25
25
  describe "#from_url" do
26
26
  let(:url){ "the_url" }
27
- let(:html_with_results){ Test.load_fixture("on_fleek_2016-02-15.html") }
28
- let(:html_without_results){ Test.load_fixture("sisyphus_2016-02-15.html") }
27
+ let(:html_with_results){ load_fixture("on_fleek_2016-02-15.html") }
28
+ let(:html_without_results){ load_fixture("sisyphus_2016-02-15.html") }
29
29
 
30
30
  it "parses a valid word" do
31
31
  word = UrbanDictionary::Word.from_html(html_with_results)
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: urban_dictionary
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Greenberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-16 00:00:00.000000000 Z
11
+ date: 2016-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: multi_json
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ! '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ! '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '3.4'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.4'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: webmock
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: 1.22.6
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 1.22.6
83
83
  description: Interface to urbandictionary.com
@@ -88,9 +88,9 @@ executables:
88
88
  extensions: []
89
89
  extra_rdoc_files: []
90
90
  files:
91
- - .gitignore
92
- - .rspec
93
- - .travis.yml
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - ".travis.yml"
94
94
  - CHANGELOG.md
95
95
  - Gemfile
96
96
  - LICENSE.md
@@ -111,6 +111,7 @@ files:
111
111
  - spec/spec_helper.rb
112
112
  - spec/urban_dictionary/cli_spec.rb
113
113
  - spec/urban_dictionary/entry_spec.rb
114
+ - spec/urban_dictionary/formatters_spec.rb
114
115
  - spec/urban_dictionary/word_spec.rb
115
116
  - spec/urban_dictionary_spec.rb
116
117
  - urban_dictionary.gemspec
@@ -123,17 +124,17 @@ require_paths:
123
124
  - lib
124
125
  required_ruby_version: !ruby/object:Gem::Requirement
125
126
  requirements:
126
- - - ! '>='
127
+ - - ">="
127
128
  - !ruby/object:Gem::Version
128
129
  version: '0'
129
130
  required_rubygems_version: !ruby/object:Gem::Requirement
130
131
  requirements:
131
- - - ! '>='
132
+ - - ">="
132
133
  - !ruby/object:Gem::Version
133
134
  version: '0'
134
135
  requirements: []
135
136
  rubyforge_project: urban_dictionary
136
- rubygems_version: 2.5.2
137
+ rubygems_version: 2.4.5
137
138
  signing_key:
138
139
  specification_version: 4
139
140
  summary: Interface to urbandictionary.com
@@ -146,5 +147,6 @@ test_files:
146
147
  - spec/spec_helper.rb
147
148
  - spec/urban_dictionary/cli_spec.rb
148
149
  - spec/urban_dictionary/entry_spec.rb
150
+ - spec/urban_dictionary/formatters_spec.rb
149
151
  - spec/urban_dictionary/word_spec.rb
150
152
  - spec/urban_dictionary_spec.rb