opinions 0.0.1
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.
- 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
|