thumbtack 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 +4 -4
- data/lib/thumbtack.rb +2 -1
- data/lib/thumbtack/adapters/basic_adapter.rb +83 -0
- data/lib/thumbtack/client.rb +26 -19
- data/lib/thumbtack/hash_to_digest.rb +12 -7
- data/lib/thumbtack/note.rb +1 -1
- data/lib/thumbtack/note_summary.rb +1 -1
- data/lib/thumbtack/post.rb +1 -1
- data/lib/thumbtack/posts.rb +13 -5
- data/lib/thumbtack/suggestion.rb +18 -4
- data/lib/thumbtack/symbolize_keys.rb +22 -0
- data/lib/thumbtack/types/boolean.rb +1 -1
- data/lib/thumbtack/types/date.rb +1 -1
- data/lib/thumbtack/types/date_time.rb +1 -1
- data/lib/thumbtack/types/identity.rb +1 -1
- data/lib/thumbtack/types/integer.rb +1 -1
- data/lib/thumbtack/types/length_validation.rb +10 -8
- data/lib/thumbtack/types/md5.rb +16 -3
- data/lib/thumbtack/types/range_validation.rb +5 -3
- data/lib/thumbtack/types/tags.rb +16 -3
- data/lib/thumbtack/types/text.rb +1 -1
- data/lib/thumbtack/types/title.rb +1 -1
- data/lib/thumbtack/types/url.rb +1 -1
- data/lib/thumbtack/version.rb +1 -1
- data/test/test_helper.rb +2 -2
- data/test/thumbtack/client_test.rb +29 -1
- data/test/thumbtack/integration/basic_adapter_test.rb +24 -0
- data/test/thumbtack/note_summary_test.rb +1 -1
- data/test/thumbtack/notes_test.rb +34 -34
- data/test/thumbtack/post_test.rb +1 -1
- data/test/thumbtack/posts_test.rb +113 -95
- data/test/thumbtack/specification_test.rb +2 -1
- data/test/thumbtack/suggestion_test.rb +4 -4
- data/test/thumbtack/tags_test.rb +30 -24
- data/test/thumbtack/types/date_test.rb +2 -2
- data/test/thumbtack/types/date_time_test.rb +4 -3
- data/test/thumbtack/types/identity_test.rb +1 -1
- data/test/thumbtack/types/md5_test.rb +3 -3
- data/test/thumbtack/types/tags_test.rb +2 -2
- data/test/thumbtack/types/text_test.rb +2 -2
- data/test/thumbtack/user_test.rb +10 -6
- metadata +26 -11
- data/lib/thumbtack/types.rb +0 -9
- data/test/thumbtack/integration/client_test.rb +0 -29
@@ -1,7 +1,8 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module Thumbtack
|
2
4
|
module Types
|
3
5
|
# Handles validation of values within a certain range
|
4
|
-
# Pinboard
|
5
6
|
#
|
6
7
|
# @api private
|
7
8
|
class RangeValidation
|
@@ -15,15 +16,16 @@ module Thumbtack
|
|
15
16
|
# @param [Range] range
|
16
17
|
# the range of valid values
|
17
18
|
#
|
18
|
-
# @return [
|
19
|
+
# @return [self]
|
19
20
|
#
|
20
21
|
# @raise [Types::ValidationError]
|
21
|
-
# if the value is not
|
22
|
+
# if the value is not within the range
|
22
23
|
def self.validate(value, range)
|
23
24
|
unless range.cover?(value)
|
24
25
|
fail ValidationError,
|
25
26
|
"#{value} must be between #{range.begin} and #{range.end}"
|
26
27
|
end
|
28
|
+
self
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
data/lib/thumbtack/types/tags.rb
CHANGED
@@ -19,13 +19,13 @@ module Thumbtack
|
|
19
19
|
# @param [String, Array<String>] value
|
20
20
|
# a single tag or an array of many tags
|
21
21
|
#
|
22
|
-
# @return [
|
22
|
+
# @return [self]
|
23
23
|
#
|
24
24
|
# @raise [Types::ValidationError]
|
25
|
-
# if any
|
25
|
+
# if any tags contain commas or are longer than 255 characters
|
26
26
|
def self.validate(value)
|
27
27
|
Array(value).each do |tag|
|
28
|
-
unless
|
28
|
+
unless tag_valid?(tag)
|
29
29
|
fail ValidationError,
|
30
30
|
"#{tag} cannot contain commas or be longer than 255 characters"
|
31
31
|
end
|
@@ -53,6 +53,19 @@ module Thumbtack
|
|
53
53
|
def self.from_parameter(parameter)
|
54
54
|
parameter.split(SEPARATOR)
|
55
55
|
end
|
56
|
+
|
57
|
+
# If true, the tag is valid
|
58
|
+
#
|
59
|
+
# @param [String] tag
|
60
|
+
# a tag to validate
|
61
|
+
#
|
62
|
+
# @return [Boolean]
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
def self.tag_valid?(tag)
|
66
|
+
tag.length < MAXIMUM_LENGTH && !tag.include?(INVALID_CHARACTER)
|
67
|
+
end
|
68
|
+
private_class_method :tag_valid?
|
56
69
|
end
|
57
70
|
end
|
58
71
|
end
|
data/lib/thumbtack/types/text.rb
CHANGED
data/lib/thumbtack/types/url.rb
CHANGED
data/lib/thumbtack/version.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -11,9 +11,9 @@ def mock_client_get(url, params, response)
|
|
11
11
|
client
|
12
12
|
end
|
13
13
|
|
14
|
-
def mock_client_action(url, params
|
14
|
+
def mock_client_action(url, params)
|
15
15
|
client = Minitest::Mock.new
|
16
|
-
client.expect(:action,
|
16
|
+
client.expect(:action, { 'result' => 'done' }, [url, params].compact)
|
17
17
|
client
|
18
18
|
end
|
19
19
|
|
@@ -4,7 +4,8 @@ require 'test_helper'
|
|
4
4
|
|
5
5
|
class ClientTest < Minitest::Test
|
6
6
|
def setup
|
7
|
-
@
|
7
|
+
@adapter = Minitest::Mock.new
|
8
|
+
@client = Client.new(nil, nil, adapter: @adapter)
|
8
9
|
end
|
9
10
|
|
10
11
|
def test_posts
|
@@ -22,4 +23,31 @@ class ClientTest < Minitest::Test
|
|
22
23
|
def test_notes
|
23
24
|
assert_instance_of Notes, @client.notes
|
24
25
|
end
|
26
|
+
|
27
|
+
def test_default_adapter
|
28
|
+
assert_kind_of Adapters::BasicAdapter, Client.new(nil, nil).adapter
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_get
|
32
|
+
@adapter.expect(:get,
|
33
|
+
{ 'posts' => [] },
|
34
|
+
['/posts/recent', { tag: 'thumbtack' }])
|
35
|
+
@client.get('/posts/recent', tag: 'thumbtack')
|
36
|
+
@adapter.verify
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_action
|
40
|
+
@adapter.expect(:get, { 'result_code' => 'done' }, ['/posts/update', {}])
|
41
|
+
@client.action('/posts/update', {})
|
42
|
+
@adapter.verify
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_action_result_error
|
46
|
+
assert_raises ResultError do
|
47
|
+
@adapter.expect(:get,
|
48
|
+
{ 'result_code' => 'notdone' },
|
49
|
+
['/posts/update', {}])
|
50
|
+
@client.action('/posts/update', {})
|
51
|
+
end
|
52
|
+
end
|
25
53
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module Integration
|
6
|
+
class BasicAdapterTest < Minitest::Test
|
7
|
+
def setup
|
8
|
+
path = File.expand_path('../../../auth_token.txt', __FILE__)
|
9
|
+
auth_token = File.open(path).read.strip
|
10
|
+
@username, @token = auth_token.split(':')
|
11
|
+
@adapter = Adapters::BasicAdapter.new(@username, @token)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_requests_return_parsed_json
|
15
|
+
response = @adapter.get('/user/api_token')
|
16
|
+
assert_equal({ 'result' => @token }, response)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_request_query_parameters
|
20
|
+
response = @adapter.get('/posts/recent', tag: 'thumbtack-test-xyz123')
|
21
|
+
assert_equal([], response['posts'])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -4,29 +4,29 @@ require 'test_helper'
|
|
4
4
|
|
5
5
|
class NotesTest < Minitest::Test
|
6
6
|
def test_list
|
7
|
-
client = mock_client_get(
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
7
|
+
client = mock_client_get(
|
8
|
+
'/notes/list',
|
9
|
+
nil,
|
10
|
+
'count' => 2,
|
11
|
+
'notes' => [
|
12
|
+
{
|
13
|
+
'id' => 'cf73bfc02e00edaa1e2b',
|
14
|
+
'title' => 'Paul Graham on Hirin\' The Ladies',
|
15
|
+
'hash' => '0bbca3cba9246bbbda2c',
|
16
|
+
'created_at' => '2011-10-28 13:37:23',
|
17
|
+
'updated_at' => '2011-10-28 13:37:23',
|
18
|
+
'length' => '890'
|
19
|
+
},
|
20
|
+
{
|
21
|
+
'id' => '8e5d6964bb810e0050b0',
|
22
|
+
'title' => 'StarCraft beta coming this week!',
|
23
|
+
'hash' => '0c9c30f60cadabd31415',
|
24
|
+
'created_at' => '2010-02-11 03:46:56',
|
25
|
+
'updated_at' => '2010-02-11 03:47:47',
|
26
|
+
'length' => '153'
|
27
|
+
}
|
28
|
+
]
|
29
|
+
)
|
30
30
|
notes = Notes.new(client)
|
31
31
|
result = notes.list
|
32
32
|
|
@@ -36,17 +36,17 @@ class NotesTest < Minitest::Test
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def test_get
|
39
|
-
client = mock_client_get(
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
39
|
+
client = mock_client_get(
|
40
|
+
'/notes/8e5d6964bb810e0050b0',
|
41
|
+
nil,
|
42
|
+
'id' => '8e5d6964bb810e0050b0',
|
43
|
+
'title' => 'StarCraft beta coming this week!',
|
44
|
+
'text' => 'This is a test note',
|
45
|
+
'hash' => '0c9c30f60cadabd31415',
|
46
|
+
'created_at' => '2010-02-11 03:46:56',
|
47
|
+
'updated_at' => '2010-02-11 03:47:47',
|
48
|
+
'length' => 19
|
49
|
+
)
|
50
50
|
notes = Notes.new(client)
|
51
51
|
result = notes.get('8e5d6964bb810e0050b0')
|
52
52
|
assert_equal '8e5d6964bb810e0050b0', result.id
|
data/test/thumbtack/post_test.rb
CHANGED
@@ -25,6 +25,6 @@ class PostTest < Minitest::Test
|
|
25
25
|
assert_equal DateTime.new(2014, 6, 29, 16, 57, 45), post.time
|
26
26
|
assert_equal true, post.shared
|
27
27
|
assert_equal false, post.toread
|
28
|
-
assert_equal
|
28
|
+
assert_equal %w(test123 another), post.tags
|
29
29
|
end
|
30
30
|
end
|
@@ -4,9 +4,11 @@ require 'test_helper'
|
|
4
4
|
|
5
5
|
class PostsTest < Minitest::Test
|
6
6
|
def test_update
|
7
|
-
client = mock_client_get(
|
8
|
-
|
9
|
-
|
7
|
+
client = mock_client_get(
|
8
|
+
'/posts/update',
|
9
|
+
nil,
|
10
|
+
'update_time' => '2014-06-26T19:01:33Z'
|
11
|
+
)
|
10
12
|
posts = Posts.new(client)
|
11
13
|
|
12
14
|
assert_equal DateTime.new(2014, 6, 26, 19, 1, 33), posts.update
|
@@ -14,10 +16,11 @@ class PostsTest < Minitest::Test
|
|
14
16
|
end
|
15
17
|
|
16
18
|
def test_add
|
17
|
-
client = mock_client_action(
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
client = mock_client_action(
|
20
|
+
'/posts/add',
|
21
|
+
url: 'http://example.org',
|
22
|
+
description: 'example.org'
|
23
|
+
)
|
21
24
|
posts = Posts.new(client)
|
22
25
|
|
23
26
|
assert_equal posts, posts.add('http://example.org', 'example.org')
|
@@ -25,22 +28,28 @@ class PostsTest < Minitest::Test
|
|
25
28
|
end
|
26
29
|
|
27
30
|
def test_add_with_tags
|
28
|
-
client = mock_client_action(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
client = mock_client_action(
|
32
|
+
'/posts/add',
|
33
|
+
url: 'http://example.org',
|
34
|
+
description: 'example.org',
|
35
|
+
tags: 'thumbtack test'
|
36
|
+
)
|
33
37
|
posts = Posts.new(client)
|
34
38
|
|
35
39
|
assert_equal posts,
|
36
|
-
|
40
|
+
posts.add(
|
41
|
+
'http://example.org',
|
42
|
+
'example.org',
|
43
|
+
tags: %w(thumbtack test)
|
44
|
+
)
|
37
45
|
client.verify
|
38
46
|
end
|
39
47
|
|
40
48
|
def test_delete
|
41
|
-
client = mock_client_action(
|
42
|
-
|
43
|
-
|
49
|
+
client = mock_client_action(
|
50
|
+
'/posts/delete',
|
51
|
+
url: 'http://example.org'
|
52
|
+
)
|
44
53
|
posts = Posts.new(client)
|
45
54
|
|
46
55
|
assert_equal posts, posts.delete('http://example.org')
|
@@ -48,23 +57,23 @@ class PostsTest < Minitest::Test
|
|
48
57
|
end
|
49
58
|
|
50
59
|
def test_get
|
51
|
-
client = mock_client_get(
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
client = mock_client_get(
|
61
|
+
'/posts/get',
|
62
|
+
{ url: 'http://example.org' },
|
63
|
+
'date' => '2014-06-29T16:57:45Z',
|
64
|
+
'user' => 'nwjsmith',
|
65
|
+
'posts' => [{
|
66
|
+
'href' => 'http://example.org',
|
67
|
+
'description' => 'example.org',
|
68
|
+
'extended' => '',
|
69
|
+
'meta' => '46ca40b9b92ee0ea1284785a5d2a9b38',
|
70
|
+
'hash' => 'dab521de65f9250b4cca7383feef67dc',
|
71
|
+
'time' => '2014-06-29T16:57:45Z',
|
72
|
+
'shared' => 'yes',
|
73
|
+
'toread' => 'no',
|
74
|
+
'tags' => 'test123'
|
75
|
+
}]
|
76
|
+
)
|
68
77
|
posts = Posts.new(client)
|
69
78
|
response = posts.get(url: 'http://example.org')
|
70
79
|
|
@@ -74,23 +83,23 @@ class PostsTest < Minitest::Test
|
|
74
83
|
end
|
75
84
|
|
76
85
|
def test_recent
|
77
|
-
client = mock_client_get(
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
86
|
+
client = mock_client_get(
|
87
|
+
'/posts/recent',
|
88
|
+
{ tag: 'webdev' },
|
89
|
+
'date' => '2014-06-29T16:57:45Z',
|
90
|
+
'user' => 'nwjsmith',
|
91
|
+
'posts' => [{
|
92
|
+
'href' => 'http://example.org',
|
93
|
+
'description' => 'example.org',
|
94
|
+
'extended' => '',
|
95
|
+
'meta' => '46ca40b9b92ee0ea1284785a5d2a9b38',
|
96
|
+
'hash' => 'dab521de65f9250b4cca7383feef67dc',
|
97
|
+
'time' => '2014-06-29T16:57:45Z',
|
98
|
+
'shared' => 'yes',
|
99
|
+
'toread' => 'no',
|
100
|
+
'tags' => 'webdev'
|
101
|
+
}]
|
102
|
+
)
|
94
103
|
posts = Posts.new(client)
|
95
104
|
response = posts.recent(tag: 'webdev')
|
96
105
|
|
@@ -100,19 +109,23 @@ class PostsTest < Minitest::Test
|
|
100
109
|
end
|
101
110
|
|
102
111
|
def test_all
|
103
|
-
client = mock_client_get(
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
client = mock_client_get(
|
113
|
+
'/posts/all',
|
114
|
+
{ tag: 'webdev' },
|
115
|
+
[
|
116
|
+
{
|
117
|
+
'href' => 'http://example.org',
|
118
|
+
'description' => 'example.org',
|
119
|
+
'extended' => '',
|
120
|
+
'meta' => '46ca40b9b92ee0ea1284785a5d2a9b38',
|
121
|
+
'hash' => 'dab521de65f9250b4cca7383feef67dc',
|
122
|
+
'time' => '2014-06-29T16:57:45Z',
|
123
|
+
'shared' => 'yes',
|
124
|
+
'toread' => 'no',
|
125
|
+
'tags' => 'webdev'
|
126
|
+
}
|
127
|
+
]
|
128
|
+
)
|
116
129
|
posts = Posts.new(client)
|
117
130
|
response = posts.all(tag: 'webdev')
|
118
131
|
|
@@ -122,12 +135,14 @@ class PostsTest < Minitest::Test
|
|
122
135
|
end
|
123
136
|
|
124
137
|
def test_suggest
|
125
|
-
client = mock_client_get(
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
138
|
+
client = mock_client_get(
|
139
|
+
'/posts/suggest',
|
140
|
+
{ url: 'http://blog.com' },
|
141
|
+
[
|
142
|
+
{ 'popular' => %w(blog blogs people) },
|
143
|
+
{ 'recommended' => %w(blog writing weblog) }
|
144
|
+
]
|
145
|
+
)
|
131
146
|
posts = Posts.new(client)
|
132
147
|
response = posts.suggest('http://blog.com')
|
133
148
|
|
@@ -137,35 +152,38 @@ class PostsTest < Minitest::Test
|
|
137
152
|
end
|
138
153
|
|
139
154
|
def test_dates
|
140
|
-
client = mock_client_get(
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
155
|
+
client = mock_client_get(
|
156
|
+
'/posts/dates',
|
157
|
+
{ tag: 'argentina' },
|
158
|
+
'user' => 'user',
|
159
|
+
'tag' => 'argentina',
|
160
|
+
'dates' => {
|
161
|
+
'2010-11-29' => '5',
|
162
|
+
'2010-11-28' => '15',
|
163
|
+
'2010-11-26' => '2',
|
164
|
+
'2010-11-25' => '2',
|
165
|
+
'2010-11-23' => '7',
|
166
|
+
'2010-11-22' => '20',
|
167
|
+
'2010-11-21' => '16',
|
168
|
+
'2010-11-19' => '4'
|
169
|
+
}
|
170
|
+
)
|
156
171
|
posts = Posts.new(client)
|
157
172
|
response = posts.dates(tag: 'argentina')
|
158
173
|
|
159
|
-
assert_equal(
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
174
|
+
assert_equal(
|
175
|
+
{
|
176
|
+
Date.new(2010, 11, 29) => 5,
|
177
|
+
Date.new(2010, 11, 28) => 15,
|
178
|
+
Date.new(2010, 11, 26) => 2,
|
179
|
+
Date.new(2010, 11, 25) => 2,
|
180
|
+
Date.new(2010, 11, 23) => 7,
|
181
|
+
Date.new(2010, 11, 22) => 20,
|
182
|
+
Date.new(2010, 11, 21) => 16,
|
183
|
+
Date.new(2010, 11, 19) => 4
|
184
|
+
},
|
185
|
+
response
|
186
|
+
)
|
169
187
|
client.verify
|
170
188
|
end
|
171
189
|
end
|