opinions 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +18 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +183 -0
- data/Rakefile +30 -0
- data/lib/opinions.rb +270 -0
- data/lib/opinions/version.rb +3 -0
- data/opinions.gemspec +27 -0
- data/test/acceptance_test_key_loader.rb +20 -0
- data/test/acceptance_test_opinions_opinion.rb +110 -0
- data/test/acceptance_test_opinions_opinionated_mixin.rb +140 -0
- data/test/acceptance_test_opinions_pollable_mixin.rb +111 -0
- data/test/integration_test_opinions_opinion.rb +60 -0
- data/test/integration_test_opinions_opinionated_mixin.rb +70 -0
- data/test/integration_test_opinions_pollable_mixin.rb +71 -0
- data/test/opinions_integration_test_redis.conf +6 -0
- data/test/test_helper.rb +112 -0
- data/test/unit_test_opinions_key_builder.rb +56 -0
- data/test/unit_test_opinions_opinion.rb +72 -0
- metadata +137 -0
data/opinions.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/opinions/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
|
6
|
+
gem.authors = ["Lee Hambley"]
|
7
|
+
gem.email = ["lee.hambley@gmail.com"]
|
8
|
+
gem.description = %q{A toolkit for storing user votes/opinions in Redis}
|
9
|
+
gem.summary = %q{Opinions allows the storage of opinions in Redis, a fast and atomic structured data store. If one's users hate, love, appreciate, despise or just-don-t-care, one can store that easily via a simple API.}
|
10
|
+
gem.homepage = ""
|
11
|
+
|
12
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
13
|
+
gem.files = `git ls-files`.split("\n")
|
14
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
gem.name = "opinions"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = Opinions::VERSION
|
18
|
+
|
19
|
+
gem.add_dependency('redis')
|
20
|
+
|
21
|
+
gem.add_development_dependency('minitest', ['>= 2.11.3', '< 2.12.0'])
|
22
|
+
gem.add_development_dependency('autotest')
|
23
|
+
gem.add_development_dependency('turn')
|
24
|
+
|
25
|
+
gem.add_development_dependency('daemon_controller')
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Opinions
|
4
|
+
|
5
|
+
class AcceptanceTestOpinionsKeyLoader < MiniTest::Acceptance::TestCase
|
6
|
+
|
7
|
+
def test_it_should_call_find_for_both_keys
|
8
|
+
|
9
|
+
example_object = ExampleObject.new(123)
|
10
|
+
example_target = ExampleTarget.new(456)
|
11
|
+
|
12
|
+
kl = KeyLoader.new("ExampleTarget:opinion:123")
|
13
|
+
|
14
|
+
assert_equal example_object, kl.object
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Opinions
|
4
|
+
|
5
|
+
class AcceptanceTestOpinionsOpinion < MiniTest::Acceptance::TestCase
|
6
|
+
|
7
|
+
def test_checking_if_an_opinion_exists_checks_both_sides_of_the_relationship
|
8
|
+
|
9
|
+
example_target = ::ExampleTarget.new
|
10
|
+
example_object = ::ExampleObject.new
|
11
|
+
|
12
|
+
example_object.id = 123
|
13
|
+
example_target.id = 456
|
14
|
+
|
15
|
+
opinion = Opinion.new({ target: example_target,
|
16
|
+
object: example_object,
|
17
|
+
opinion: :example })
|
18
|
+
|
19
|
+
Opinions.backend = ::MiniTest::Mock.new
|
20
|
+
|
21
|
+
Opinions.backend.expect(:read_sub_key, false, [opinion.target_key, example_object.id.to_s])
|
22
|
+
Opinions.backend.expect(:read_sub_key, false, [opinion.object_key, example_target.id.to_s])
|
23
|
+
|
24
|
+
refute opinion.exists?
|
25
|
+
|
26
|
+
Opinions.backend.verify
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_creating_an_opinion_creates_both_sides_of_the_relationship
|
31
|
+
|
32
|
+
t = Time.now.utc
|
33
|
+
|
34
|
+
example_target = ::ExampleTarget.new
|
35
|
+
example_object = ::ExampleObject.new
|
36
|
+
|
37
|
+
example_target.id = 123
|
38
|
+
example_object.id = 456
|
39
|
+
|
40
|
+
opinion = Opinion.new({ target: example_target,
|
41
|
+
object: example_object,
|
42
|
+
opinion: :example })
|
43
|
+
|
44
|
+
Opinions.backend = ::MiniTest::Mock.new
|
45
|
+
Opinions.backend.expect(:write_keys, true, [{ opinion.target_key => {example_object.id.to_s => t},
|
46
|
+
opinion.object_key => {example_target.id.to_s => t}}])
|
47
|
+
|
48
|
+
opinion.persist(time: t)
|
49
|
+
|
50
|
+
Opinions.backend.verify
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_removing_an_opinion_removes_both_sides_of_the_relationship
|
55
|
+
|
56
|
+
t = Time.now.utc
|
57
|
+
|
58
|
+
example_target = ::ExampleTarget.new
|
59
|
+
example_object = ::ExampleObject.new
|
60
|
+
|
61
|
+
example_target.id = 123
|
62
|
+
example_object.id = 456
|
63
|
+
|
64
|
+
opinion = Opinion.new({ target: example_target,
|
65
|
+
object: example_object,
|
66
|
+
opinion: :example })
|
67
|
+
|
68
|
+
Opinions.backend = ::MiniTest::Mock.new
|
69
|
+
Opinions.backend.expect(:remove_sub_keys, true, [[ [opinion.target_key, example_object.id.to_s],
|
70
|
+
[opinion.object_key, example_target.id.to_s] ]])
|
71
|
+
|
72
|
+
opinion.remove
|
73
|
+
|
74
|
+
Opinions.backend.verify
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_removing_one_opinion_without_removing_other_opinions
|
79
|
+
|
80
|
+
t = Time.now.utc
|
81
|
+
|
82
|
+
example_target = ::ExampleTarget.new
|
83
|
+
example_object_one = ::ExampleObject.new
|
84
|
+
example_object_two = ::ExampleObject.new
|
85
|
+
|
86
|
+
example_target.id = 123
|
87
|
+
example_object_one.id = 456
|
88
|
+
example_object_two.id = 789
|
89
|
+
|
90
|
+
opinion_one = Opinion.new({ target: example_target,
|
91
|
+
object: example_object_one,
|
92
|
+
opinion: :example })
|
93
|
+
|
94
|
+
opinion_two = Opinion.new({ target: example_target,
|
95
|
+
object: example_object_two,
|
96
|
+
opinion: :example })
|
97
|
+
|
98
|
+
Opinions.backend = ::MiniTest::Mock.new
|
99
|
+
Opinions.backend.expect(:remove_sub_keys, true, [[ [opinion_one.target_key, example_object_one.id.to_s],
|
100
|
+
[opinion_one.object_key, example_target.id.to_s] ]])
|
101
|
+
|
102
|
+
opinion_one.remove
|
103
|
+
|
104
|
+
Opinions.backend.verify
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Opinions
|
4
|
+
|
5
|
+
class AcceptanceTestOpinionsOpinionated < MiniTest::Acceptance::TestCase
|
6
|
+
|
7
|
+
def test_mixing_in_opinionated_makes_the_opinions_method_available
|
8
|
+
|
9
|
+
refute ExampleObject.respond_to?(:opinions)
|
10
|
+
ExampleObject.send(:include, Opinionated)
|
11
|
+
assert ExampleObject.respond_to?(:opinions)
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_using_the_pollable_opinions_method_registers_them_as_supported_opinions
|
16
|
+
|
17
|
+
ExampleObject.send(:include, Opinionated)
|
18
|
+
ExampleObject.send(:opinions, :example_one, :example_two, :example_three)
|
19
|
+
|
20
|
+
assert_equal [:example_one, :example_two, :example_three], ExampleObject.registered_opinions
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_the_registered_opinions_have_their_instance_methods_created
|
25
|
+
|
26
|
+
ExampleObject.send(:include, Opinionated)
|
27
|
+
ExampleObject.send(:opinions, :example_opinion)
|
28
|
+
|
29
|
+
assert ExampleObject.new.respond_to?(:example_opinion)
|
30
|
+
assert ExampleObject.new.respond_to?(:cancel_example_opinion)
|
31
|
+
assert ExampleObject.new.respond_to?(:example_opinion_opinions)
|
32
|
+
assert ExampleObject.new.respond_to?(:have_example_opinion_on)
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_creating_an_opinion_persits_it_to_the_backend
|
37
|
+
|
38
|
+
t = Time.now.utc
|
39
|
+
|
40
|
+
ExampleObject.send(:include, Opinionated)
|
41
|
+
ExampleObject.send(:opinions, :example_opinion)
|
42
|
+
|
43
|
+
example_object = ExampleObject.new
|
44
|
+
example_object.id = 123
|
45
|
+
|
46
|
+
example_target = ExampleTarget.new
|
47
|
+
example_target.id = 456
|
48
|
+
|
49
|
+
Opinions.backend = ::MiniTest::Mock.new
|
50
|
+
Opinions.backend.expect(:write_keys, true, [{ 'ExampleObject:example_opinion:123:ExampleTarget' => {'456' => t},
|
51
|
+
'ExampleTarget:example_opinion:456:ExampleObject' => {'123' => t} }])
|
52
|
+
|
53
|
+
assert_equal true, example_object.example_opinion(example_target, t)
|
54
|
+
|
55
|
+
Opinions.backend.verify
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_calcelling_an_opinion_removes_both_sides_of_the_relationship_from_the_backend
|
60
|
+
|
61
|
+
t = Time.now.utc
|
62
|
+
|
63
|
+
ExampleObject.send(:include, Opinionated)
|
64
|
+
ExampleObject.send(:opinions, :example_opinion)
|
65
|
+
|
66
|
+
example_object = ExampleObject.new
|
67
|
+
example_object.id = 123
|
68
|
+
|
69
|
+
example_target = ExampleTarget.new
|
70
|
+
example_target.id = 456
|
71
|
+
|
72
|
+
Opinions.backend = ::MiniTest::Mock.new
|
73
|
+
Opinions.backend.expect(:remove_sub_keys, true, [[["ExampleTarget:example_opinion:456:ExampleObject", "123"],
|
74
|
+
["ExampleObject:example_opinion:123:ExampleTarget", "456"]]])
|
75
|
+
|
76
|
+
assert_equal true, example_object.cancel_example_opinion(example_target)
|
77
|
+
|
78
|
+
Opinions.backend.verify
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_opinions_retrieved_from_the_backend_en_masse
|
83
|
+
|
84
|
+
t = Time.now.utc
|
85
|
+
|
86
|
+
ExampleObject.send(:include, Opinionated)
|
87
|
+
ExampleObject.send(:opinions, :example_opinion)
|
88
|
+
|
89
|
+
example_target = ExampleTarget.new
|
90
|
+
example_target.id = '456'
|
91
|
+
|
92
|
+
example_object = ExampleObject.new
|
93
|
+
example_object.id = '123'
|
94
|
+
|
95
|
+
Opinions.backend = ::MiniTest::Mock.new
|
96
|
+
Opinions.backend.expect(:keys_matching, ["ExampleObject:example_opinion:123:ExampleTarget"], ["ExampleObject:example_opinion:123*"])
|
97
|
+
Opinions.backend.expect(:read_key, {"456" => t}, ["ExampleObject:example_opinion:123:ExampleTarget"])
|
98
|
+
|
99
|
+
expected_opinion = Opinion.new(target: example_target,
|
100
|
+
object: example_object,
|
101
|
+
opinion: :example_opinion,
|
102
|
+
created_at: t)
|
103
|
+
|
104
|
+
assert_equal expected_opinion, example_object.example_opinion_opinions.first
|
105
|
+
|
106
|
+
Opinions.backend.verify
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_opinions_checking_if_an_object_has_a_vote_for_a_target
|
111
|
+
|
112
|
+
t = Time.now.utc
|
113
|
+
|
114
|
+
ExampleObject.send(:include, Opinionated)
|
115
|
+
ExampleObject.send(:opinions, :example_opinion)
|
116
|
+
|
117
|
+
example_target = ExampleTarget.new
|
118
|
+
example_target.id = '456'
|
119
|
+
|
120
|
+
example_object = ExampleObject.new
|
121
|
+
example_object.id = '123'
|
122
|
+
|
123
|
+
Opinions.backend = ::MiniTest::Mock.new
|
124
|
+
Opinions.backend.expect(:keys_matching, ["ExampleObject:example_opinion:123:ExampleTarget"], ["ExampleObject:example_opinion:123*"])
|
125
|
+
Opinions.backend.expect(:read_key, {"456" => t}, ["ExampleObject:example_opinion:123:ExampleTarget"])
|
126
|
+
|
127
|
+
expected_opinion = Opinion.new(target: example_target,
|
128
|
+
object: example_object,
|
129
|
+
opinion: :example_opinion,
|
130
|
+
created_at: t)
|
131
|
+
|
132
|
+
assert example_object.have_example_opinion_on(example_target)
|
133
|
+
|
134
|
+
Opinions.backend.verify
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Opinions
|
4
|
+
|
5
|
+
class AcceptanceTestOpinionsPollable < MiniTest::Acceptance::TestCase
|
6
|
+
|
7
|
+
def test_mixing_in_pollable_makes_the_opinions_method_available
|
8
|
+
|
9
|
+
refute ExampleTarget.respond_to?(:opinions)
|
10
|
+
ExampleTarget.send(:include, Pollable)
|
11
|
+
assert ExampleTarget.respond_to?(:opinions)
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_using_the_pollable_opinions_method_registers_them_as_supported_opinions
|
16
|
+
|
17
|
+
ExampleTarget.send(:include, Pollable)
|
18
|
+
ExampleTarget.send(:opinions, :example_one, :example_two, :example_three)
|
19
|
+
|
20
|
+
assert_equal [:example_one, :example_two, :example_three], ExampleTarget.registered_opinions
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_the_registered_opinions_have_their_instance_methods_created
|
25
|
+
|
26
|
+
ExampleTarget.send(:include, Pollable)
|
27
|
+
ExampleTarget.send(:opinions, :example_opinion)
|
28
|
+
|
29
|
+
assert ExampleTarget.new.respond_to?(:example_opinion_by)
|
30
|
+
assert ExampleTarget.new.respond_to?(:cancel_example_opinion_by)
|
31
|
+
assert ExampleTarget.new.respond_to?(:example_opinion_votes)
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_creating_an_opinion_persits_it_to_the_backend
|
36
|
+
|
37
|
+
t = Time.now.utc
|
38
|
+
|
39
|
+
ExampleTarget.send(:include, Pollable)
|
40
|
+
ExampleTarget.send(:opinions, :example_opinion)
|
41
|
+
|
42
|
+
example_object = ExampleObject.new
|
43
|
+
example_object.id = 123
|
44
|
+
|
45
|
+
example_target = ExampleTarget.new
|
46
|
+
example_target.id = 456
|
47
|
+
|
48
|
+
Opinions.backend = ::MiniTest::Mock.new
|
49
|
+
Opinions.backend.expect(:write_keys, true, [{ 'ExampleObject:example_opinion:123:ExampleTarget' => {'456' => t},
|
50
|
+
'ExampleTarget:example_opinion:456:ExampleObject' => {'123' => t} }])
|
51
|
+
|
52
|
+
assert_equal true, example_target.example_opinion_by(example_object, t)
|
53
|
+
|
54
|
+
Opinions.backend.verify
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_calcelling_an_opinion_removes_both_sides_of_the_relationship_from_the_backend
|
59
|
+
|
60
|
+
t = Time.now.utc
|
61
|
+
|
62
|
+
ExampleTarget.send(:include, Pollable)
|
63
|
+
ExampleTarget.send(:opinions, :example_opinion)
|
64
|
+
|
65
|
+
example_object = ExampleObject.new
|
66
|
+
example_object.id = 123
|
67
|
+
|
68
|
+
example_target = ExampleTarget.new
|
69
|
+
example_target.id = 456
|
70
|
+
|
71
|
+
Opinions.backend = ::MiniTest::Mock.new
|
72
|
+
Opinions.backend.expect(:remove_sub_keys, true, [[["ExampleTarget:example_opinion:456:ExampleObject", "123"],
|
73
|
+
["ExampleObject:example_opinion:123:ExampleTarget", "456"]]])
|
74
|
+
|
75
|
+
assert_equal true, example_target.cancel_example_opinion_by(example_object)
|
76
|
+
|
77
|
+
Opinions.backend.verify
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_opinions_retrieved_from_the_backend_en_masse
|
82
|
+
|
83
|
+
t = Time.now.utc
|
84
|
+
|
85
|
+
ExampleTarget.send(:include, Pollable)
|
86
|
+
ExampleTarget.send(:opinions, :example_opinion)
|
87
|
+
|
88
|
+
example_target = ExampleTarget.new
|
89
|
+
example_target.id = '456'
|
90
|
+
|
91
|
+
example_object = ExampleObject.new
|
92
|
+
example_object.id = '123'
|
93
|
+
|
94
|
+
Opinions.backend = ::MiniTest::Mock.new
|
95
|
+
Opinions.backend.expect(:keys_matching, ["ExampleTarget:example_opinion:456:ExampleObject"], ["ExampleTarget:example_opinion:456*"])
|
96
|
+
Opinions.backend.expect(:read_key, {"123" => t}, ["ExampleTarget:example_opinion:456:ExampleObject"])
|
97
|
+
|
98
|
+
expected_opinion = Opinion.new(target: example_target,
|
99
|
+
object: example_object,
|
100
|
+
opinion: :example_opinion,
|
101
|
+
created_at: t)
|
102
|
+
|
103
|
+
assert_equal expected_opinion, example_target.example_opinion_votes.first
|
104
|
+
|
105
|
+
Opinions.backend.verify
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Opinions
|
4
|
+
|
5
|
+
class IntegrationTestOpinionsOpinion < MiniTest::Integration::TestCase
|
6
|
+
|
7
|
+
def test_opinions_do_not_exist_until_persisted
|
8
|
+
|
9
|
+
example_object = ExampleObject.new
|
10
|
+
example_object.id = 123
|
11
|
+
|
12
|
+
example_target = ExampleTarget.new
|
13
|
+
example_target.id = 456
|
14
|
+
|
15
|
+
opinion = Opinion.new(object: example_object, target: example_target, opinion: :example)
|
16
|
+
|
17
|
+
refute opinion.exists?
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_opinions_exist_once_persisted
|
22
|
+
|
23
|
+
example_object = ExampleObject.new
|
24
|
+
example_object.id = 123
|
25
|
+
|
26
|
+
example_target = ExampleTarget.new
|
27
|
+
example_target.id = 456
|
28
|
+
|
29
|
+
opinion_one = Opinion.new(object: example_object, target: example_target, opinion: :example)
|
30
|
+
|
31
|
+
refute opinion_one.exists?
|
32
|
+
assert opinion_one.persist
|
33
|
+
assert opinion_one.exists?
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_opinions_that_are_the_same_can_be_treated_as_equal
|
38
|
+
|
39
|
+
example_object = ExampleObject.new
|
40
|
+
example_object.id = 123
|
41
|
+
|
42
|
+
example_target = ExampleTarget.new
|
43
|
+
example_target.id = 456
|
44
|
+
|
45
|
+
opinion_one = Opinion.new(object: example_object, target: example_target, opinion: :example)
|
46
|
+
opinion_two = Opinion.new(object: example_object, target: example_target, opinion: :example)
|
47
|
+
|
48
|
+
refute opinion_one.exists?
|
49
|
+
refute opinion_two.exists?
|
50
|
+
|
51
|
+
[opinion_one, opinion_two].sample.persist
|
52
|
+
|
53
|
+
assert opinion_one.exists?
|
54
|
+
assert opinion_two.exists?
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|