thumbtack 1.0.0 → 1.1.0
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 +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
|