daodalus-moped 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +7 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +72 -0
  5. data/LICENCE.md +9 -0
  6. data/README.md +316 -0
  7. data/Rakefile +8 -0
  8. data/daodalus-moped.gemspec +24 -0
  9. data/lib/daodalus.rb +29 -0
  10. data/lib/daodalus/connection.rb +19 -0
  11. data/lib/daodalus/dao.rb +35 -0
  12. data/lib/daodalus/dsl.rb +21 -0
  13. data/lib/daodalus/dsl/aggregation/group.rb +88 -0
  14. data/lib/daodalus/dsl/aggregation/limit.rb +23 -0
  15. data/lib/daodalus/dsl/aggregation/match.rb +35 -0
  16. data/lib/daodalus/dsl/aggregation/project.rb +79 -0
  17. data/lib/daodalus/dsl/aggregation/skip.rb +23 -0
  18. data/lib/daodalus/dsl/aggregation/sort.rb +29 -0
  19. data/lib/daodalus/dsl/aggregation/unwind.rb +23 -0
  20. data/lib/daodalus/dsl/aggregations.rb +44 -0
  21. data/lib/daodalus/dsl/clause.rb +19 -0
  22. data/lib/daodalus/dsl/matchers.rb +87 -0
  23. data/lib/daodalus/dsl/queries.rb +31 -0
  24. data/lib/daodalus/dsl/query.rb +42 -0
  25. data/lib/daodalus/dsl/select.rb +43 -0
  26. data/lib/daodalus/dsl/update.rb +86 -0
  27. data/lib/daodalus/dsl/updates.rb +71 -0
  28. data/lib/daodalus/dsl/where.rb +30 -0
  29. data/lib/daodalus/invalid_connection_error.rb +7 -0
  30. data/lib/daodalus/invalid_query_error.rb +4 -0
  31. data/spec/lib/daodalus/connection_spec.rb +22 -0
  32. data/spec/lib/daodalus/dao_spec.rb +26 -0
  33. data/spec/lib/daodalus/dsl/aggregation/group_spec.rb +92 -0
  34. data/spec/lib/daodalus/dsl/aggregation/limit_spec.rb +22 -0
  35. data/spec/lib/daodalus/dsl/aggregation/match_spec.rb +32 -0
  36. data/spec/lib/daodalus/dsl/aggregation/project_spec.rb +74 -0
  37. data/spec/lib/daodalus/dsl/aggregation/skip_spec.rb +22 -0
  38. data/spec/lib/daodalus/dsl/aggregation/sort_spec.rb +36 -0
  39. data/spec/lib/daodalus/dsl/aggregation/unwind_spec.rb +24 -0
  40. data/spec/lib/daodalus/dsl/clause_spec.rb +22 -0
  41. data/spec/lib/daodalus/dsl/query_spec.rb +35 -0
  42. data/spec/lib/daodalus/dsl/select_spec.rb +46 -0
  43. data/spec/lib/daodalus/dsl/update_spec.rb +113 -0
  44. data/spec/lib/daodalus/dsl/where_spec.rb +133 -0
  45. data/spec/lib/daodalus/dsl_spec.rb +12 -0
  46. data/spec/pointless_coverage_spec.rb +9 -0
  47. data/spec/spec_helper.rb +18 -0
  48. data/spec/support/mongo_cleaner.rb +12 -0
  49. metadata +208 -0
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ describe DAO do
5
+
6
+ it 'takes a collection and connection name' do
7
+ expect { DAO.new(:animalhouse, :cats, :animalhouse) }.to_not raise_error
8
+ end
9
+
10
+ it 'is not necessary to specify the connection name' do
11
+ expect { DAO.new(:animalhouse, :cats) }.to_not raise_error
12
+ end
13
+
14
+ let (:dao) { DAO.new(:animalhouse, :cats) }
15
+
16
+ it 'holds a connection to the mongo DB collection' do
17
+ dao.coll.should be_a Moped::Collection
18
+ end
19
+
20
+ it 'delegates basic mongo methods to its coll' do
21
+ dao.coll.should_receive(:find)
22
+ dao.find
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ module Aggregation
6
+ describe Group do
7
+
8
+ let (:dao) { DAO.new(:animalhouse, :cats) }
9
+
10
+ before do
11
+ dao.insert('name' => 'Terry',
12
+ 'paws' => 3,
13
+ 'likes' => ['tuna', 'catnip'],
14
+ 'foods' => [{'type' => 'dry', 'name' => 'go cat'},
15
+ {'type' => 'wet', 'name' => 'whiskas'}])
16
+
17
+ dao.insert('name' => 'Jemima',
18
+ 'paws' => 3,
19
+ 'likes' => ['tuna', 'ginger beer'],
20
+ 'foods' => [{'type' => 'cat', 'name' => 'go cat'},
21
+ {'type' => 'dog', 'name' => 'whiskas'}])
22
+ end
23
+
24
+ it 'can group on a single field' do
25
+ dao.group_by('$foods.type').aggregate.should eq [
26
+ {"_id"=>["cat", "dog"]},
27
+ {"_id"=>["dry", "wet"]}
28
+ ]
29
+ end
30
+
31
+ it 'can group by a hash of fields' do
32
+ dao.group_by(cat: '$name', brand: '$foods.name').aggregate.should eq [
33
+ {"_id"=>{"cat"=>"Jemima", "brand"=>["go cat", "whiskas"]}},
34
+ {"_id"=>{"cat"=>"Terry", "brand"=>["go cat", "whiskas"]}}
35
+ ]
36
+ end
37
+
38
+ it 'can sum a set of fields' do
39
+ dao.group_by(1).sum("$paws").as(:paws).aggregate.should eq [{"_id"=>1, "paws"=>6}]
40
+ end
41
+
42
+ it 'can build up a unique set of aggregate values' do
43
+ dao.insert('name' => 'Terry', 'paws' => 3)
44
+ dao.group_by("$paws").distinct("$name").as(:cats).aggregate.should eq [
45
+ {"_id"=>3, "cats"=>["Jemima", "Terry"]}
46
+ ]
47
+ end
48
+
49
+ it 'can build up a non-unique set of aggregate values' do
50
+ dao.insert('name' => 'Terry', 'paws' => 3)
51
+ dao.group_by(:"$paws").collect("$name").as(:cats).aggregate.should eq [
52
+ {"_id"=>3, "cats"=>["Terry", "Jemima", "Terry"]}
53
+ ]
54
+ end
55
+
56
+ it 'can get the first value for an aggregate field' do
57
+ dao.group_by(1).first('$name').as(:name).aggregate.should eq [
58
+ {"_id"=>1, "name"=>"Terry"}
59
+ ]
60
+ end
61
+
62
+ it 'can get the last value for an aggregate field' do
63
+ dao.group_by(1).last('$name').as(:name).aggregate.should eq [
64
+ {"_id"=>1, "name"=>"Jemima"}
65
+ ]
66
+ end
67
+
68
+ it 'can get the min value for an aggregate field' do
69
+ dao.insert('name' => 'Terry', 'paws' => 7)
70
+ dao.group_by(1).min('$paws').as(:paws).aggregate.should eq [
71
+ {"_id"=>1, "paws"=>3}
72
+ ]
73
+ end
74
+
75
+ it 'can get the max value for an aggregate field' do
76
+ dao.insert('name' => 'Terry', 'paws' => 7)
77
+ dao.group_by(1).max('$paws').as(:paws).aggregate.should eq [
78
+ {"_id"=>1, "paws"=>7}
79
+ ]
80
+ end
81
+
82
+ it 'can get the average value for an aggregate field' do
83
+ dao.insert('name' => 'Terry', 'paws' => 24)
84
+ dao.group_by(1).average('$paws').as(:paws).aggregate.should eq [
85
+ {"_id"=>1, "paws"=>10}
86
+ ]
87
+ end
88
+
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ module Aggregation
6
+ describe Limit do
7
+
8
+ let (:dao) { DAO.new(:animalhouse, :cats) }
9
+
10
+ before do
11
+ dao.insert('name' => 'Terry')
12
+ dao.insert('name' => 'Jemima')
13
+ end
14
+
15
+ it 'allows an aggregation query to be limited' do
16
+ dao.limit(1).project(:name).aggregate.should eq ['name' => 'Terry']
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ module Aggregation
6
+ describe Match do
7
+
8
+ let (:dao) { DAO.new(:animalhouse, :cats) }
9
+
10
+ before do
11
+ dao.insert('name' => 'Terry',
12
+ 'paws' => 3,
13
+ 'likes' => ['tuna', 'catnip'],
14
+ 'foods' => [{'type' => 'dry', 'name' => 'go cat'},
15
+ {'type' => 'wet', 'name' => 'whiskas'}])
16
+ end
17
+
18
+ it 'allows queries to be made on the pipeline' do
19
+ dao.match(:name).eq('Terry').and(paws: 3).aggregate.should have(1).item
20
+ dao.match(:name).eq('Terry').aggregate.first.fetch('paws').should eq 3
21
+ end
22
+
23
+ it 'also works with the logical query operators' do
24
+ dao.match.any(
25
+ dao.where(:name).eq('Terrence'),
26
+ dao.where(:name).eq('Terry')
27
+ ).aggregate.should have(1).item
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ module Aggregation
6
+ describe Project do
7
+
8
+ let (:dao) { DAO.new(:animalhouse, :cats) }
9
+
10
+ before do
11
+ dao.insert('name' => 'Terry',
12
+ 'nickname' => 'Terry',
13
+ 'breed' => 'Tabby',
14
+ 'paws' => 3,
15
+ 'likes' => ['tuna', 'catnip'],
16
+ 'foods' => [{'type' => 'dry', 'name' => 'go cat'},
17
+ {'type' => 'wet', 'name' => 'whiskas'}])
18
+
19
+ end
20
+
21
+ it 'can project a list of fields' do
22
+ dao.project(:name, :paws, 'foods.name').aggregate.should eq [
23
+ {'name' => 'Terry', 'paws' => 3, "foods"=>[{"name"=>"go cat"}, {"name"=>"whiskas"}] }
24
+ ]
25
+ end
26
+
27
+ it 'can rename fields' do
28
+ dao.project(feet: '$paws').aggregate.should eq ['feet' => 3]
29
+ end
30
+
31
+ it 'can be chained with other projects' do
32
+ dao.project(:paws).and(cat: '$name').aggregate.should eq ['paws' => 3, 'cat' => 'Terry']
33
+ end
34
+
35
+ it 'can alias fields using "as"' do
36
+ dao.project(:paws).and("$name").as(:cat).aggregate.should eq ['paws' => 3, 'cat' => 'Terry']
37
+ end
38
+
39
+ it 'implements the #eq function' do
40
+ dao.project("$name").eq("$nickname").as(:thingy).aggregate.should eq [ 'thingy' => true ]
41
+ dao.project("$name").eq("$breed").as(:thingy).aggregate.should eq [ 'thingy' => false ]
42
+ dao.project("$name").eq('Terry').as(:thingy).aggregate.should eq [ 'thingy' => true ]
43
+ end
44
+
45
+ it 'implements the #plus function' do
46
+ dao.project("$paws", 1).plus("$paws", 4).as(:thingy).aggregate.should eq [ 'thingy' => 11 ]
47
+ end
48
+
49
+ it 'implements the #divide function' do
50
+ dao.project("$paws").divided_by("$paws").as(:thingy).aggregate.should eq [ 'thingy' => 1 ]
51
+ end
52
+
53
+ it 'implements the #multiply function' do
54
+ dao.project("$paws").multiplied_by("$paws").as(:thingy).aggregate.should eq [ 'thingy' => 9 ]
55
+ end
56
+
57
+ it 'implements the #subtract function' do
58
+ dao.project("$paws").minus("$paws").as(:thingy).aggregate.should eq [ 'thingy' => 0 ]
59
+ end
60
+
61
+ it 'implements the #mod function' do
62
+ dao.project("$paws").mod(5).as(:thingy).aggregate.should eq [ 'thingy' => 3 ]
63
+ end
64
+
65
+ it 'can create nested documents' do
66
+ dao.project(
67
+ dao.project("$paws").as(:feet).and(name: "$name"),
68
+ ).as(:cat).aggregate.should eq [{"cat"=>{"feet"=>3, "name"=>"Terry"}}]
69
+ end
70
+
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ module Aggregation
6
+ describe Skip do
7
+
8
+ let (:dao) { DAO.new(:animalhouse, :cats) }
9
+
10
+ before do
11
+ dao.insert('name' => 'Terry')
12
+ dao.insert('name' => 'Jemima')
13
+ end
14
+
15
+ it 'allows an aggregation query to skip some records' do
16
+ dao.skip(1).project(:name).aggregate.should eq ['name' => 'Jemima']
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ module Aggregation
6
+ describe Sort do
7
+
8
+ let (:dao) { DAO.new(:animalhouse, :cats) }
9
+
10
+ before do
11
+ dao.insert('name' => 'Terry', paws: 2)
12
+ dao.insert('name' => 'Jemima', paws: 4)
13
+ end
14
+
15
+ it 'allows an aggregation query to be sorted' do
16
+ dao.sort(name: 1).project(:name).aggregate.should eq [
17
+ {"name"=>"Jemima"},
18
+ {"name"=>"Terry"}
19
+ ]
20
+ dao.sort(name: -1).project(:name).aggregate.should eq [
21
+ {"name"=>"Terry"},
22
+ {"name"=>"Jemima"}
23
+ ]
24
+ end
25
+
26
+ it 'accepts symbols for sort order' do
27
+ dao.sort(paws: :desc).project(:name).aggregate.should eq [
28
+ {"name"=>"Jemima"},
29
+ {"name"=>"Terry"}
30
+ ]
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ module Aggregation
6
+ describe Unwind do
7
+
8
+ let (:dao) { DAO.new(:animalhouse, :cats) }
9
+
10
+ before do
11
+ dao.insert('name' => 'Terry', 'likes' => ['tuna', 'cakes'])
12
+ end
13
+
14
+ it 'allows an aggregation query to be unwound' do
15
+ dao.unwind(:likes).project(:name, :likes).aggregate.should eq [
16
+ {"name"=>"Terry", "likes"=>"tuna"},
17
+ {"name"=>"Terry", "likes"=>"cakes"}
18
+ ]
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ describe Clause do
6
+
7
+ let (:dao) { DAO.new(:animalhouse, :cats) }
8
+
9
+ it 'allows you to get the current query' do
10
+ dao.where(:name).eq('Trevor').to_query.should be_a Hash
11
+ end
12
+
13
+ it 'allows you to get the current projection' do
14
+ dao.where(:name).eq('Trevor').to_projection.should be_a Hash
15
+ end
16
+
17
+ it 'allows you to get the current update' do
18
+ dao.where(:name).eq('Trevor').to_update.should be_a Hash
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ describe Query do
6
+
7
+ let (:dao) { DAO.new(:animalhouse, :cats) }
8
+ let (:query) { dao.query }
9
+
10
+ it 'can have a where clause added to it' do
11
+ query.where(paws: 3).wheres.should eq ({paws: 3})
12
+ end
13
+
14
+ it 'can have multiple where clauses added to it' do
15
+ q = query.where('paws' => 3).where('tail' => 'waggy')
16
+ q.wheres.should eq ({'paws' => 3, 'tail' => 'waggy'})
17
+ end
18
+
19
+ it 'merges clauses where possible' do
20
+ q = query.where('paws' => { '$gte' => 3}).where('paws' => {'$lte' => 6})
21
+ q.wheres.should eq ({'paws' => {'$gte'=>3, '$lte'=>6}})
22
+ end
23
+
24
+ it 'raises an error if two clauses cannot be merged' do
25
+ expect { query.where('paws' => 3).where('paws' => 4) }.to raise_error InvalidQueryError
26
+ end
27
+
28
+ it 'can have select clauses added to it' do
29
+ q = query.select('paws' => 1, 'tail' => 1)
30
+ q.selects.should eq ({'_id' => 0, 'paws' => 1, 'tail' => 1})
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ describe Select do
6
+
7
+ let (:dao) { DAO.new(:animalhouse, :cats) }
8
+
9
+ before do
10
+ dao.insert('name' => 'Terry',
11
+ 'paws' => 3,
12
+ 'likes' => ['tuna', 'catnip'],
13
+ 'lives' => [1,2,3,4,5,6,7,8,9],
14
+ 'foods' => [{'type' => 'dry', 'name' => 'go cat'},
15
+ {'type' => 'wet', 'name' => 'whiskas'}])
16
+ end
17
+
18
+ it 'allows the selection of fields to be returned' do
19
+ dao.select(:name, :paws).find_one.value.keys.should eq ['name', 'paws']
20
+ end
21
+
22
+ it 'allows the chaining of selects' do
23
+ dao.select(:name).and(:paws).find_one.value.keys.should eq ['name', 'paws']
24
+ end
25
+
26
+ it 'allows use of the positional operator' do
27
+ query = dao.select(:foods).by_position.where(:'foods.type').eq('wet')
28
+ result = query.find_one.value
29
+ result.fetch('foods').should eq (['type' => 'wet', 'name' => 'whiskas'])
30
+ end
31
+
32
+ it 'implements #slice' do
33
+ dao.select(:lives).slice(-3).find_one.value.fetch('lives').should eq [7,8,9]
34
+ dao.select(:lives).slice(-3, 3).find_one.value.fetch('lives').should eq [7,8,9]
35
+ dao.select(:lives).slice(6, 5).find_one.value.fetch('lives').should eq [7,8,9]
36
+ end
37
+
38
+ it 'implements #elem_match' do
39
+ dao.select(:foods).elem_match(
40
+ dao.where(:type).eq(:wet)
41
+ ).find_one.value.fetch('foods').first.fetch('name').should eq 'whiskas'
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ module Daodalus
4
+ module DSL
5
+ describe Update do
6
+
7
+ let (:dao) { DAO.new(:animalhouse, :cats) }
8
+
9
+ before do
10
+ dao.insert('name' => 'Terry',
11
+ 'paws' => 3,
12
+ 'likes' => ['tuna', 'catnip'],
13
+ 'lives' => [1,2,3,4,5,6,7,8,9],
14
+ 'foods' => [{'type' => 'dry', 'name' => 'go cat'},
15
+ {'type' => 'wet', 'name' => 'whiskas'}])
16
+ end
17
+
18
+ it 'can perform upserts' do
19
+ dao.set(paws: 3).where(:name).eq('Charlie').upsert
20
+ dao.where(:name).eq('Charlie').find_one.value.merge('_id' => 1).should eq ({
21
+ '_id' => 1,
22
+ "name"=>"Charlie", "paws"=>3
23
+ })
24
+ end
25
+
26
+ it 'can perform find_and_modifys' do
27
+ dao.inc(:paws).where(:name).eq('Terry').find_and_modify
28
+ dao.where(:name).eq('Terry').find_one.value.merge('_id' => 1).should eq ({
29
+ '_id' => 1,
30
+ "name"=>"Terry", "paws"=>4, "likes"=>["tuna", "catnip"], "lives"=>[1, 2, 3, 4, 5, 6, 7, 8, 9], "foods"=>[{"type"=>"dry", "name"=>"go cat"}, {"type"=>"wet", "name"=>"whiskas"}]
31
+ })
32
+ end
33
+
34
+ it 'implements #set' do
35
+ dao.set(name: 'Terrence', paws: 2).update
36
+ dao.find_one.value.fetch('paws').should eq 2
37
+ dao.find_one.value.fetch('name').should eq 'Terrence'
38
+ end
39
+
40
+ it 'implements #unset' do
41
+ dao.unset(:name, :likes).update
42
+ dao.find_one.value.fetch('names', nil).should be_nil
43
+ dao.find_one.value.fetch('likes', nil).should be_nil
44
+ end
45
+
46
+ it 'implements #inc' do
47
+ dao.inc(:paws).update
48
+ dao.find_one.value.fetch('paws').should eq 4
49
+ end
50
+
51
+ it 'implements #dec' do
52
+ dao.dec(:paws, 2).update
53
+ dao.find_one.value.fetch('paws').should eq 1
54
+ end
55
+
56
+ it 'implements #rename' do
57
+ dao.rename(:paws, :feet).update
58
+ dao.find_one.value.fetch('feet').should eq 3
59
+ end
60
+
61
+ it 'implements #push' do
62
+ dao.push(:likes, 'food').update
63
+ dao.push(:likes, 'Marxist political economics', 'cake').update
64
+ dao.find_one.value.fetch('likes').should include 'Marxist political economics'
65
+ dao.find_one.value.fetch('likes').should include 'cake'
66
+ dao.find_one.value.fetch('likes').should include 'food'
67
+ end
68
+
69
+ it 'implements #pushAll' do
70
+ dao.push_all(:likes, ['Marxist political economics', 'cake']).update
71
+ dao.find_one.value.fetch('likes').should include 'Marxist political economics'
72
+ dao.find_one.value.fetch('likes').should include 'cake'
73
+ end
74
+
75
+ it 'implements #add_to_set' do
76
+ dao.add_to_set(:likes, 'cake').update
77
+ dao.add_to_set(:likes, 'tuna', 'cake', 'cake').update
78
+ dao.find_one.value.fetch('likes').should eq ['tuna', 'catnip', 'cake']
79
+ end
80
+
81
+ it 'implements #add_each_to_set' do
82
+ dao.add_each_to_set(:likes, ['tuna', 'cake', 'cake']).update
83
+ dao.find_one.value.fetch('likes').should eq ['tuna', 'catnip', 'cake']
84
+ end
85
+
86
+ it 'implements #pop_first' do
87
+ dao.pop_first(:likes).update
88
+ dao.find_one.value.fetch('likes').should eq ['catnip']
89
+ end
90
+
91
+ it 'implements #pop_last' do
92
+ dao.pop_last(:likes).update
93
+ dao.find_one.value.fetch('likes').should eq ['tuna']
94
+ end
95
+
96
+ it 'implements #pull' do
97
+ dao.pull(:likes, 'tuna').update
98
+ dao.find_one.value.fetch('likes').should eq ['catnip']
99
+ end
100
+
101
+ it 'allows passing multipl values to #pull' do
102
+ dao.pull(:likes, 'tuna', 'catnip').update
103
+ dao.find_one.value.fetch('likes').should eq []
104
+ end
105
+
106
+ it 'implements #pull_all' do
107
+ dao.pull_all(:likes, ['catnip', 'tuna']).update
108
+ dao.find_one.value.fetch('likes').should eq []
109
+ end
110
+
111
+ end
112
+ end
113
+ end