urban 0.1.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +0 -5
- data/HISTORY.rdoc +25 -0
- data/README.rdoc +32 -8
- data/Rakefile +24 -0
- data/bin/urban +0 -1
- data/lib/urban/cli.rb +75 -31
- data/lib/urban/dictionary.rb +21 -17
- data/lib/urban/version.rb +1 -1
- data/lib/urban/web.rb +19 -5
- data/test/data/missing.html +272 -0
- data/test/minitest/stop_light.rb +57 -0
- data/test/test_helper.rb +11 -17
- data/test/urban/cli_test.rb +175 -64
- data/test/urban/dictionary_test.rb +22 -6
- data/test/urban/web_test.rb +45 -10
- data/urban.gemspec +4 -5
- metadata +80 -47
@@ -0,0 +1,57 @@
|
|
1
|
+
class MiniTest::StopLight
|
2
|
+
ESC = "\e["
|
3
|
+
NND = "#{ESC}0m"
|
4
|
+
|
5
|
+
attr_reader :io
|
6
|
+
|
7
|
+
def initialize io
|
8
|
+
@io = io
|
9
|
+
end
|
10
|
+
|
11
|
+
def red str
|
12
|
+
normal_color(31, str)
|
13
|
+
end
|
14
|
+
|
15
|
+
def yellow str
|
16
|
+
normal_color(33, str)
|
17
|
+
end
|
18
|
+
|
19
|
+
def green str
|
20
|
+
normal_color(32, str)
|
21
|
+
end
|
22
|
+
|
23
|
+
def normal_color(color_code, str)
|
24
|
+
"#{ESC}#{color_code}m#{str}#{NND}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def print(o)
|
28
|
+
case o
|
29
|
+
when '.'; io.print green(o)
|
30
|
+
when 'E', 'F'; io.print red(o)
|
31
|
+
when 'S'; io.print yellow(o)
|
32
|
+
else; io.print o
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def puts(*o)
|
37
|
+
o.map! do |str|
|
38
|
+
case str
|
39
|
+
when /Failure:/, /Error:/, /[1-9]+ failures/, /[1-9]+ errors/;
|
40
|
+
red(str)
|
41
|
+
when /Skipped:/
|
42
|
+
yellow(str)
|
43
|
+
when /0 failures, 0 errors/;
|
44
|
+
green(str).gsub(/([1-9]+ skips)/, yellow('\1'))
|
45
|
+
else;
|
46
|
+
str.gsub(/([1-9]+ skips)/, yellow('\1'))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
super
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing(msg, *args)
|
53
|
+
io.send(msg, *args)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
MiniTest::Unit.output = MiniTest::StopLight.new(MiniTest::Unit.output)
|
data/test/test_helper.rb
CHANGED
@@ -1,34 +1,28 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
+
gem 'minitest' if RUBY_VERSION > '1.9'
|
4
5
|
require 'minitest/autorun'
|
5
6
|
require 'urban'
|
6
7
|
require 'urban/cli'
|
8
|
+
require 'minitest/stop_light'
|
9
|
+
require 'ostruct'
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
:definitions => [
|
11
|
-
'Something that is made up on the spot and given little time to gather and present. Usually referring to speeches that are given only a few minutes to prepare for.',
|
11
|
+
TEST_ENTRY = Urban::Dictionary::Entry.new('impromptu',
|
12
|
+
[ 'Something that is made up on the spot and given little time to gather and present. Usually referring to speeches that are given only a few minutes to prepare for.',
|
12
13
|
'On the spot',
|
13
|
-
'Something that is made up on the spot. Can also mean a speech that was made with little or no preparation.'
|
14
|
-
|
14
|
+
'Something that is made up on the spot. Can also mean a speech that was made with little or no preparation.' ],
|
15
|
+
'http://www.urbandictionary.com/define.php?term=impromptu')
|
16
|
+
|
17
|
+
EMPTY_ENTRY = Urban::Dictionary::Entry.new('gubble', nil, nil)
|
15
18
|
|
16
19
|
def load_file(filename)
|
17
20
|
IO.read(File.expand_path("../data/#{filename}", __FILE__))
|
18
21
|
end
|
19
22
|
|
20
|
-
['refute', 'assert'].each do |action|
|
21
|
-
eval <<-EOM
|
22
|
-
def #{action}_cli_prints(matches, &block)
|
23
|
-
out, err = capture_io(&block)
|
24
|
-
[*matches].each { |match| #{action}_match(match, out) }
|
25
|
-
end
|
26
|
-
EOM
|
27
|
-
end
|
28
|
-
|
29
23
|
module Stub
|
30
24
|
def stub(name, &block)
|
31
|
-
|
32
|
-
|
25
|
+
singleton_class = class << self; self; end
|
26
|
+
singleton_class.send(:define_method, name, &block)
|
33
27
|
end
|
34
28
|
end
|
data/test/urban/cli_test.rb
CHANGED
@@ -1,101 +1,212 @@
|
|
1
1
|
require 'test_helper'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'socket'
|
4
|
+
require 'shellwords'
|
2
5
|
|
3
6
|
class CLITest < MiniTest::Unit::TestCase
|
4
7
|
|
8
|
+
HELP_SCREEN = <<-EOS
|
9
|
+
Usage: urban [OPTION]... [PHRASE]
|
10
|
+
Search http://urbandictionary.com for definitions of phrases
|
11
|
+
|
12
|
+
Options:
|
13
|
+
-a, --all List all definitions
|
14
|
+
-r, --random Return a random phrase and definition
|
15
|
+
-u, --url Print the definition's url after the definition
|
16
|
+
-h, --help Show this message
|
17
|
+
-v, --version Show version information
|
18
|
+
-l, --list DEPRECATED please use --all or -a instead
|
19
|
+
|
20
|
+
Examples:
|
21
|
+
urban cookie monster Search for "cookie monster" and print its
|
22
|
+
first definition
|
23
|
+
urban -a cookie monster Search for "cookie monster" and print all of
|
24
|
+
its available definitions
|
25
|
+
urban -r Print a random phrase and its first definition
|
26
|
+
urban -ra Print a random phrase and all of its available
|
27
|
+
definitions
|
28
|
+
|
29
|
+
EOS
|
30
|
+
|
5
31
|
def setup
|
6
32
|
@program = Urban::CLI.new
|
7
33
|
end
|
8
34
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
/-r, --random\s*Find random word on urban dictionary/,
|
15
|
-
/-h, --help\s*Show this message/,
|
16
|
-
/-version\s*Show version/
|
17
|
-
]
|
18
|
-
assert_cli_prints(expectations) { @program.run(["-h"]) }
|
35
|
+
# Helpers
|
36
|
+
def assert_program_output(argument_variations, stdout=nil, stderr=nil)
|
37
|
+
argument_variations.each do |args|
|
38
|
+
assert_output(stdout, stderr) { @program.run(Shellwords.shellwords(args)) }
|
39
|
+
end
|
19
40
|
end
|
20
41
|
|
21
|
-
|
22
|
-
args = ['-v']
|
23
|
-
assert_cli_prints(/^Urban \d+\.\d+\.\d+ \(c\) Thomas Miller$/) { @program.run(args) }
|
24
|
-
end
|
42
|
+
class CLIArgumentParsingTest < CLITest
|
25
43
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
44
|
+
# Helpers
|
45
|
+
def assert_flag_is_set(name)
|
46
|
+
["-#{name.chars.first}", "--#{name}"].each do |args|
|
47
|
+
options = @program.send(:parse, [args])
|
48
|
+
assert_equal(true, options.send(name))
|
49
|
+
end
|
50
|
+
end
|
30
51
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
52
|
+
# Tests
|
53
|
+
def test_defaults
|
54
|
+
assert_silent do
|
55
|
+
options = @program.send(:parse, [])
|
56
|
+
assert_equal(false, options.help)
|
57
|
+
assert_equal(false, options.version)
|
58
|
+
assert_equal(false, options.random)
|
59
|
+
assert_equal(false, options.all)
|
60
|
+
assert_equal('', options.phrase)
|
61
|
+
end
|
62
|
+
end
|
35
63
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
assert(actual.random, 'Args --random Expected true, returned false')
|
64
|
+
def test_phrase
|
65
|
+
assert_silent do
|
66
|
+
options = @program.send(:parse, ['foo bar'])
|
67
|
+
assert_equal('foo bar', options.phrase)
|
68
|
+
end
|
42
69
|
end
|
43
|
-
end
|
44
70
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
actual = @program.send(:parse, ['--list'])
|
50
|
-
assert(actual.list, 'Args: --list; Expected true, returned false')
|
71
|
+
def test_help_flag
|
72
|
+
assert_silent do
|
73
|
+
assert_flag_is_set('help')
|
74
|
+
end
|
51
75
|
end
|
52
|
-
end
|
53
76
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
77
|
+
def test_version_flag
|
78
|
+
assert_silent do
|
79
|
+
assert_flag_is_set('version')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_random_flag
|
84
|
+
assert_silent do
|
85
|
+
assert_flag_is_set('random')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_all_flag
|
90
|
+
assert_silent do
|
91
|
+
assert_flag_is_set('all')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_all_flag
|
96
|
+
assert_silent do
|
97
|
+
assert_flag_is_set('url')
|
98
|
+
end
|
60
99
|
end
|
61
100
|
end
|
62
101
|
|
63
|
-
class
|
102
|
+
class CLIRunnerStandardOutputTest < CLITest
|
103
|
+
|
104
|
+
SINGLE_DEFINITION = "\n#{TEST_ENTRY.phrase.upcase}\n\n#{TEST_ENTRY.definitions.first}\n\n"
|
105
|
+
MULTIPLE_DEFINITIONS = "\n#{TEST_ENTRY.phrase.upcase}\n\n#{TEST_ENTRY.definitions.join("\n\n")}\n\n"
|
106
|
+
DEFINITION_WITH_URL = "\n#{TEST_ENTRY.phrase.upcase}\n\n#{TEST_ENTRY.definitions.first}\n\nURL: #{TEST_ENTRY.url}\n\n"
|
107
|
+
|
64
108
|
def setup
|
65
|
-
@dictionary = MiniTest::Mock.new
|
66
109
|
super
|
110
|
+
@dictionary = MiniTest::Mock.new
|
111
|
+
end
|
112
|
+
|
113
|
+
# Tests
|
114
|
+
def test_help_flag_prints_help
|
115
|
+
assert_output(HELP_SCREEN) { @program.run([]) }
|
67
116
|
end
|
68
117
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
118
|
+
def test_version_flag_prints_version
|
119
|
+
['-v', '--v'].each do |args|
|
120
|
+
assert_output("Urban #{Urban::VERSION} (c) Thomas Miller\n") { @program.run([args]) }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_random_flag_prints_single_definition
|
125
|
+
@program.dictionary = @dictionary.expect(:random, TEST_ENTRY)
|
126
|
+
argument_variations = ['-r', '--random']
|
127
|
+
assert_program_output(argument_variations, SINGLE_DEFINITION)
|
128
|
+
@dictionary.verify
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_phrase_prints_single_definition
|
132
|
+
@program.dictionary = @dictionary.expect(:search, TEST_ENTRY, ['impromptu'])
|
133
|
+
argument_variations = ['impromptu']
|
134
|
+
assert_program_output(argument_variations, SINGLE_DEFINITION)
|
135
|
+
@dictionary.verify
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_random_and_all_flag_prints_multiple_definitions
|
139
|
+
@program.dictionary = @dictionary.expect(:random, TEST_ENTRY)
|
140
|
+
argument_variations = ['-ra', '-r -a', '--random -a', '-r --all', '--all --random']
|
141
|
+
assert_program_output(argument_variations, MULTIPLE_DEFINITIONS)
|
74
142
|
@dictionary.verify
|
75
143
|
end
|
76
144
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
assert_cli_prints(expected) { @program.run(args) }
|
145
|
+
def test_phrase_and_all_flag_prints_multiple_definitions
|
146
|
+
@program.dictionary = @dictionary.expect(:search, TEST_ENTRY, ['impromptu'])
|
147
|
+
argument_variations = ['impromptu -a', '--all impromptu']
|
148
|
+
assert_program_output(argument_variations, MULTIPLE_DEFINITIONS)
|
82
149
|
@dictionary.verify
|
83
150
|
end
|
84
151
|
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
assert_cli_prints(expected) { @program.run(['impromptu']) }
|
152
|
+
def test_random_and_url_flag_prints_definition_with_url
|
153
|
+
@program.dictionary = @dictionary.expect(:random, TEST_ENTRY)
|
154
|
+
argument_variations = ['-ru', '-r -u', '--random -u', '-r --url', '--url --random']
|
155
|
+
assert_program_output(argument_variations, DEFINITION_WITH_URL)
|
90
156
|
@dictionary.verify
|
91
157
|
end
|
92
158
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
assert_cli_prints(expected) { @program.run(args) }
|
159
|
+
def test_phrase_and_url_flag_prints_definition_with_url
|
160
|
+
@program.dictionary = @dictionary.expect(:search, TEST_ENTRY, ['impromptu'])
|
161
|
+
argument_variations = ['impromptu -u', '--url impromptu']
|
162
|
+
assert_program_output(argument_variations, DEFINITION_WITH_URL)
|
98
163
|
@dictionary.verify
|
99
164
|
end
|
165
|
+
|
166
|
+
def test_list_flag_prints_deprecation_warning
|
167
|
+
expected = /WARNING: --list and -l are deprecated please use --all or -a instead/
|
168
|
+
@program.dictionary = @dictionary.expect(:search, TEST_ENTRY, ['impromptu'])
|
169
|
+
@program.dictionary = @dictionary.expect(:random, TEST_ENTRY)
|
170
|
+
stdout, stederr = capture_io { @program.run(Shellwords.shellwords('--list impromptu')) }
|
171
|
+
assert_match expected, stdout
|
172
|
+
stdou, stederr = capture_io { @program.run(Shellwords.shellwords('-rl')) }
|
173
|
+
assert_match expected, stdout
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class CLIRunnerErrorOutputTest < CLITest
|
178
|
+
|
179
|
+
ERROR_MISSING_PHRASE = "urban: no definitions found for #{EMPTY_ENTRY.phrase.upcase}.\n"
|
180
|
+
ERROR_NO_INTERNET = "urban: no internet connection available.\n"
|
181
|
+
ERROR_INVALID_OPTION = <<-EOE
|
182
|
+
urban: invalid option: -b
|
183
|
+
Try `urban --help' for more information.
|
184
|
+
EOE
|
185
|
+
|
186
|
+
def setup
|
187
|
+
super
|
188
|
+
end
|
189
|
+
|
190
|
+
# Tests
|
191
|
+
def test_search_missing_phrase_prints_error
|
192
|
+
dictionary = MiniTest::Mock.new
|
193
|
+
@program.dictionary = dictionary.expect(:search, EMPTY_ENTRY, ['gubble'])
|
194
|
+
assert_program_output(['gubble'], nil, ERROR_MISSING_PHRASE)
|
195
|
+
dictionary.verify
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_search_missing_phrase_prints_error
|
199
|
+
dictionary = (Object.new).extend Stub
|
200
|
+
dictionary.stub(:search) { |phrase| raise SocketError }
|
201
|
+
@program.dictionary = dictionary
|
202
|
+
assert_program_output(['gubble'], nil, ERROR_NO_INTERNET)
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_invalid_option_prints_help
|
206
|
+
dictionary = (Object.new).extend Stub
|
207
|
+
dictionary.stub(:search) { |phrase| raise OptionParser::InvalidOption }
|
208
|
+
@program.dictionary = dictionary
|
209
|
+
assert_program_output(['-b'], nil, ERROR_INVALID_OPTION)
|
210
|
+
end
|
100
211
|
end
|
101
212
|
end
|
@@ -4,18 +4,34 @@ class DictionaryTest < MiniTest::Unit::TestCase
|
|
4
4
|
|
5
5
|
def setup
|
6
6
|
@web_service = MiniTest::Mock.new
|
7
|
-
@dictionary = Urban::Dictionary
|
7
|
+
@dictionary = Urban::Dictionary
|
8
|
+
|
9
|
+
@response = OpenStruct.new
|
10
|
+
@response.url = 'http://www.urbandictionary.com/define.php?term=impromptu'
|
11
|
+
@response.stream = load_file('impromptu.html')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_process_extracts_elements_from_html
|
15
|
+
entry = @dictionary.send(:process, @response )
|
16
|
+
assert_equal(TEST_ENTRY, entry)
|
8
17
|
end
|
9
18
|
|
10
19
|
def test_dictionary_calls_random
|
11
|
-
@dictionary.web_service = @web_service.expect(:
|
12
|
-
assert_equal(
|
20
|
+
@dictionary.web_service = @web_service.expect(:random, @response)
|
21
|
+
assert_equal(TEST_ENTRY, @dictionary.random)
|
13
22
|
@web_service.verify
|
14
23
|
end
|
15
24
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
25
|
+
def test_dictionary_calls_search
|
26
|
+
@dictionary.web_service = @web_service.expect(:search, @response, ['impromptu'])
|
27
|
+
assert_equal(TEST_ENTRY, @dictionary.search('impromptu'))
|
28
|
+
@web_service.verify
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_dictionary_returns_empty_for_missing_phrases
|
32
|
+
@response.stream = load_file('missing.html')
|
33
|
+
@dictionary.web_service = @web_service.expect(:search, @response, ['gubble'])
|
34
|
+
assert_equal(EMPTY_ENTRY, @dictionary.search('gubble'))
|
19
35
|
@web_service.verify
|
20
36
|
end
|
21
37
|
end
|
data/test/urban/web_test.rb
CHANGED
@@ -3,19 +3,54 @@ require 'test_helper'
|
|
3
3
|
class WebTest < MiniTest::Unit::TestCase
|
4
4
|
|
5
5
|
def setup
|
6
|
-
@
|
7
|
-
@web_service.stub(:open) { |arg| return arg; }
|
6
|
+
@web_module = (Object.new).extend(Urban::Web).extend(Stub)
|
8
7
|
end
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
class WebFetchTest < WebTest
|
10
|
+
def setup
|
11
|
+
super
|
12
|
+
@web_module.stub(:open) { |arg| arg }
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_fetch_with_no_params
|
16
|
+
expected = 'http://www.urbandictionary.com/test.php'
|
17
|
+
actual = @web_module.fetch('test.php')
|
18
|
+
assert_equal(expected, actual)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_fetch_with_params
|
22
|
+
expected = /http:\/\/www\.urbandictionary\.com\/test\.php\?\w+=\w+&\w+=\w+/
|
23
|
+
actual = @web_module.fetch('test.php', :name => 'foo', :term => 'bar')
|
24
|
+
assert_match(expected, actual)
|
25
|
+
end
|
14
26
|
end
|
15
27
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
28
|
+
class WebInterfaceTest < WebTest
|
29
|
+
|
30
|
+
def setup
|
31
|
+
super
|
32
|
+
@expected = OpenStruct.new
|
33
|
+
@expected.base_uri = 'http://www.urbandictionary.com/define.php?term=impromptu'
|
34
|
+
|
35
|
+
@web_module.stub(:open) do |arg|
|
36
|
+
result = OpenStruct.new
|
37
|
+
result.base_uri = 'http://www.urbandictionary.com/define.php?term=impromptu'
|
38
|
+
result
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_returns_response_for_random_word
|
43
|
+
actual = @web_module.random
|
44
|
+
|
45
|
+
assert_equal(@expected.base_uri, actual.url)
|
46
|
+
assert_equal(@expected, actual.stream)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_returns_response_for_define_with_phrase
|
50
|
+
actual = @web_module.search('cookie monster')
|
51
|
+
|
52
|
+
assert_equal(@expected.base_uri, actual.url)
|
53
|
+
assert_equal(@expected, actual.stream)
|
54
|
+
end
|
20
55
|
end
|
21
56
|
end
|