rankle 0.0.0.pre → 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6c1c94e6dadbdd8d36db346f7767bc847d9402d4
4
- data.tar.gz: 5923e83360576985bc983215e94041d6c53d2906
3
+ metadata.gz: 93e91d72d1ae47471f1be951fdf49bea1b5de6c0
4
+ data.tar.gz: e6cee95ce83201559b16638e08eefb73b1cf89ba
5
5
  SHA512:
6
- metadata.gz: 513aa6cd74b4a39425e66cd19f5ed7980523dee33b4bdd15ea46d5c8dcfc3836f5c3bec7215db8249daec2cc843192d011fb4a7b2e25c74ba58bb70d38cf48a3
7
- data.tar.gz: d244dd513e0a1ff12c339f32d21a9d16bb882b8002ecd452382b7bc389ec217bbd1e84a4bd00166d346a50bf4633d9a4a18aff9d86e28717f04e3385d6d6639f
6
+ metadata.gz: 196913721f0a56bd267fc1f1b17c13e8e4a3dde6251fb22c3a6ffecc4896bb510a9d24ecceb73712d53f50e5a26ed52b699a1fb988a392949a0813020da59f00
7
+ data.tar.gz: e3919e144ebd2a1d86f4a42a0105c7bd946567e6caef4061e7d2bd75fb29266c50ed0b4fc3065ee10bb1d6766a380a3300578cdf41893fb58609f54f1c41b79d
data/.gitignore CHANGED
@@ -34,3 +34,6 @@ Gemfile.lock
34
34
 
35
35
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
36
36
  .rvmrc
37
+
38
+ # The db directory is used by the test suite to verify the rankle install generator
39
+ /db
data/README.md CHANGED
@@ -1,10 +1,7 @@
1
- # Rankle (pre-release)
1
+ # Rankle
2
2
 
3
3
  Rankle provides multi-resource ranking. It uses a separate join table rather than a resource specific position column.
4
4
 
5
- ** Rankle is currently in a pre-release state. It is not optimized for performance and should not be used in
6
- production applications. Future work will be tracked with issues. **
7
-
8
5
  ## Installation
9
6
 
10
7
  Add this line to your application's Gemfile:
@@ -55,8 +52,8 @@ orange.position # 1
55
52
  The ranked method provides an ordered ActiveRecord::Relation:
56
53
 
57
54
  ```ruby
58
- Fruit.create! name, 'apple'
59
- Fruit.create! name, 'orange'
55
+ Fruit.create! name: 'apple'
56
+ Fruit.create! name: 'orange'
60
57
 
61
58
  Fruit.ranked.map(&:name) # ['apple', 'orange']
62
59
  ```
@@ -104,43 +101,43 @@ Fruit.ranked.map(&:name) # ['apple', 'banana', 'orange']
104
101
  Passing a symbol to the rank method with a position will update the position to that named rank:
105
102
 
106
103
  ```ruby
107
- apple = Fruit.create!
108
- orange = Fruit.create!
104
+ apple = Fruit.create! name: 'apple'
105
+ orange = Fruit.create! name: 'orange'
109
106
 
110
- apple.rank :reverse, 1
111
- orange.rank :reverse, 0
107
+ apple.rank :reverse, 1
108
+ orange.rank :reverse, 0
112
109
 
113
- apple.position # 0
114
- orange.position # 1
110
+ apple.position # 0
111
+ orange.position # 1
115
112
 
116
- apple.position :reverse # 1
117
- orange.position :reverse # 0
113
+ apple.position :reverse # 1
114
+ orange.position :reverse # 0
118
115
 
119
- Fruit.ranked.map(&:name) # ['apple', 'orange']
120
- Fruit.ranked(:reverse).map(&:name) # ['orange', 'apple']
116
+ Fruit.ranked.map(&:name) # ['apple', 'orange']
117
+ Fruit.ranked(:reverse).map(&:name) # ['orange', 'apple']
121
118
  ```
122
119
 
123
120
  Since positions are not stored with an absolute value, the available positions increases by 1 with each call to the rank method:
124
121
 
125
122
  ```ruby
126
- apple = Fruit.create!
127
- banana = Fruit.create!
128
- orange = Fruit.create!
123
+ apple = Fruit.create! name: 'apple'
124
+ banana = Fruit.create! name: 'banana'
125
+ orange = Fruit.create! name: 'orange'
129
126
 
130
- apple.rank :reverse, 2 # [apple]
131
- banana.rank :reverse, 1 # [banana, apple]
132
- orange.rank :reverse, 0 # [orange, banana, apple]
127
+ apple.rank :reverse, 2 # [apple]
128
+ banana.rank :reverse, 1 # [banana, apple]
129
+ orange.rank :reverse, 0 # [orange, banana, apple]
133
130
 
134
- apple.position # 0
135
- banana.position # 1
136
- orange.position # 2
131
+ apple.position # 0
132
+ banana.position # 1
133
+ orange.position # 2
137
134
 
138
- apple.position :reverse # 1
139
- banana.position :reverse # 2
140
- orange.position :reverse # 0
135
+ apple.position :reverse # 1
136
+ banana.position :reverse # 2
137
+ orange.position :reverse # 0
141
138
 
142
- Fruit.ranked.map(&:name) # ['apple', 'banana', 'orange']
143
- Fruit.ranked(:reverse).map(&:name) # ['orange', 'apple', 'banana']
139
+ Fruit.ranked.map(&:name) # ['apple', 'banana', 'orange']
140
+ Fruit.ranked(:reverse).map(&:name) # ['orange', 'apple', 'banana']
144
141
  ```
145
142
 
146
143
  You can bypass this issue by registering the ranking on the class:
@@ -150,9 +147,9 @@ class Fruit < ActiveRecord::Base
150
147
  ranks :reverse
151
148
  end
152
149
 
153
- apple = Fruit.create!
154
- banana = Fruit.create!
155
- orange = Fruit.create!
150
+ apple = Fruit.create! name: 'apple'
151
+ banana = Fruit.create! name: 'banana'
152
+ orange = Fruit.create! name: 'orange'
156
153
 
157
154
  apple.position # 0
158
155
  banana.position # 1
@@ -189,8 +186,8 @@ end
189
186
  class Vegetable < ActiveRecord::Base
190
187
  end
191
188
 
192
- apple = Fruit.create!
193
- carrot = Vegetable.create!
189
+ apple = Fruit.create! name: 'apple'
190
+ carrot = Vegetable.create! name: 'carrot'
194
191
 
195
192
  apple.rank :produce, 0
196
193
  carrot.rank :produce, 1
@@ -227,8 +224,8 @@ Class Vegetable
227
224
  ranks :produce
228
225
  end
229
226
 
230
- apple = Fruit.create!
231
- carrot = Vegetable.create!
227
+ apple = Fruit.create! name: 'apple'
228
+ carrot = Vegetable.create! name: 'vegetable'
232
229
 
233
230
  apple.position # 0
234
231
  carrot.position # 0
@@ -237,6 +234,29 @@ apple.position :produce # 0
237
234
  carrot.position :produce # 1
238
235
  ```
239
236
 
237
+ ## Scoped Ranking
238
+
239
+ ActiveRecord scopes work in conjunction to further restrict the ranking:
240
+
241
+ ```ruby
242
+ class Fruit
243
+ scope :berries, -> { where "name LIKE ?", '%berry' }
244
+ end
245
+
246
+ Fruit.create! name: 'apple'
247
+ Fruit.create! name: 'apricot'
248
+ Fruit.create! name: 'banana'
249
+ Fruit.create! name: 'bilberry'
250
+ Fruit.create! name: 'blackberry'
251
+ Fruit.create! name: 'blackcurrant'
252
+ Fruit.create! name: 'blueberry'
253
+ Fruit.create! name: 'boysenberry'
254
+ Fruit.create! name: 'cantaloupe'
255
+
256
+ Fruit.ranked.map(&:name) # ['apple', 'apricot', 'banana', 'bilberry', 'blackberry', 'blackcurrant', 'blueberry', 'boysenberry', 'cantaloupe']
257
+ Fruit.berries.ranked.map(&:name) # ['bilberry', 'blackberry', 'blueberry', 'boysenberry']
258
+ ```
259
+
240
260
  ## Contributing
241
261
 
242
262
  1. Fork it ( https://github.com/[my-github-username]/rankle/fork )
data/Rakefile CHANGED
@@ -1,14 +1,14 @@
1
1
  require 'bundler/gem_tasks'
2
- require 'cucumber'
3
- require 'cucumber/rake/task'
4
2
  require 'yard'
3
+ require 'rake/testtask'
5
4
 
6
- Cucumber::Rake::Task.new(:features) do |t|
7
- t.cucumber_opts = 'features --format pretty'
5
+ Rake::TestTask.new do |t|
6
+ t.test_files = FileList['test/*_test.rb']
7
+ t.verbose = true
8
8
  end
9
9
 
10
10
  YARD::Rake::YardocTask.new do |t|
11
11
  t.files = ['lib/rankle.rb']
12
12
  end
13
13
 
14
- task :default => [:features, :yard]
14
+ task :default => [:test, :yard]
@@ -7,7 +7,7 @@ module Rankle
7
7
  source_root File.expand_path('../templates/', __FILE__)
8
8
 
9
9
  def generate_migration
10
- migration_template 'migration.rb', 'db/migrate/create_rankle_index.rb'
10
+ migration_template 'migration.rb', 'db/migrate/create_rankle_indices.rb'
11
11
  end
12
12
 
13
13
  def self.next_migration_number(dir)
@@ -1,6 +1,6 @@
1
- class CreateRankleIndex < ActiveRecord::Migration
1
+ class CreateRankleIndices < ActiveRecord::Migration
2
2
  def change
3
- create_table(:rankle_index) do |t|
3
+ create_table :rankle_indices do |t|
4
4
  t.string :indexable_name
5
5
  t.integer :indexable_id
6
6
  t.string :indexable_type
@@ -9,9 +9,9 @@ class CreateRankleIndex < ActiveRecord::Migration
9
9
  t.timestamps null: false
10
10
  end
11
11
 
12
- add_index :rankle_index, :indexable_name
13
- add_index :rankle_index, :indexable_id
14
- add_index :rankle_index, :indexable_type
15
- add_index :rankle_index, :indexable_position
12
+ add_index :rankle_indices, :indexable_name
13
+ add_index :rankle_indices, :indexable_id
14
+ add_index :rankle_indices, :indexable_type
15
+ add_index :rankle_indices, :indexable_position
16
16
  end
17
17
  end
data/lib/rankle/ranker.rb CHANGED
@@ -1,18 +1,9 @@
1
1
  module Rankle
2
2
  class Ranker
3
- def self.put klass, proc
4
- @rankers ||= {}
5
- @rankers[klass] = proc
6
- end
7
-
8
- def self.get klass
9
- @rankers[klass] rescue nil
10
- end
3
+ attr_accessor :strategy
11
4
 
12
- def self.swap(first_index, second_index)
13
- first_index_position = first_index.indexable_position
14
- first_index.update_attribute(:indexable_position, second_index.indexable_position)
15
- second_index.update_attribute(:indexable_position, first_index_position)
5
+ def initialize strategy
6
+ @strategy = strategy
16
7
  end
17
8
  end
18
9
  end
@@ -1,3 +1,3 @@
1
1
  module Rankle
2
- VERSION = '0.0.0.pre'
2
+ VERSION = '0.0.0'
3
3
  end
data/lib/rankle.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'active_record'
2
+ require 'rankle_index'
2
3
  require 'rankle/ranker'
3
4
  require 'rankle/version'
4
5
 
@@ -22,28 +23,19 @@ module Rankle
22
23
  end
23
24
  end
24
25
 
25
- def ranks proc
26
- Ranker.put self, proc
26
+ def ranks strategy
27
+ RankleIndex.ranks self, Ranker.new(strategy)
27
28
  end
28
29
  end
29
30
 
30
31
  def self.ranked name = :default
31
- RankleIndex.where(indexable_name: name).order(:indexable_position).map do |duck|
32
- duck.indexable_type.classify.constantize.find(duck.indexable_id)
33
- end
32
+ RankleIndex.ranked name
34
33
  end
35
34
 
36
35
  # instance methods added to ActiveRecord models
37
36
  module InstanceMethods
38
37
  def set_default_position
39
- if Ranker.get(self.class)
40
- position = self.class.ranked.each_with_index { |record, index| break index if Ranker.get(self.class).call(self, record) }
41
- end unless Ranker.get(self.class).is_a?(Symbol)
42
- position = self.class.count - 1 if position.nil? || position.is_a?(Array)
43
- rank position
44
- if Ranker.get(self.class).is_a?(Symbol)
45
- rank Ranker.get(self.class), RankleIndex.where(indexable_name: Ranker.get(self.class)).count
46
- end
38
+ RankleIndex.set_default_position self
47
39
  end
48
40
 
49
41
  # Assigns an explicit position to the record
@@ -55,28 +47,11 @@ module Rankle
55
47
  end
56
48
 
57
49
  def rank name = :default, position
58
- rankle_index = RankleIndex.where(indexable_name: name.to_s, indexable_id: id, indexable_type: self.class).first_or_create!
59
- rankle_index_length = if name == :default
60
- RankleIndex.where(indexable_name: name.to_s, indexable_type: self.class).count
61
- else
62
- RankleIndex.where(indexable_name: name.to_s).count
63
- end
64
- position = 0 if position < 0
65
- position = rankle_index_length - 1 if position >= rankle_index_length
66
- rankle_index.update_attribute(:indexable_position, rankle_index_length - 1) unless rankle_index.indexable_position
67
- swap_distance = -1
68
- swap_distance *= -1 if rankle_index.indexable_position < position
69
- until rankle_index.indexable_position == position
70
- if name == :default
71
- Ranker.swap(rankle_index, RankleIndex.where(indexable_name: name.to_s, indexable_type: self.class, indexable_position: rankle_index.indexable_position + swap_distance).first)
72
- else
73
- Ranker.swap(rankle_index, RankleIndex.where(indexable_name: name.to_s, indexable_position: rankle_index.indexable_position + swap_distance).first)
74
- end
75
- end
50
+ RankleIndex.rank self, name, position
76
51
  end
77
52
 
78
53
  def position name = :default
79
- RankleIndex.where(indexable_name: name.to_s, indexable_id: id, indexable_type: self.class).first_or_create.indexable_position
54
+ RankleIndex.position self, name
80
55
  end
81
56
  end
82
57
  end
@@ -0,0 +1,57 @@
1
+ class RankleIndex < ActiveRecord::Base
2
+ belongs_to :indexable, polymorphic: true
3
+
4
+ @rankers = {}
5
+
6
+ def self.ranks klass, ranker
7
+ @rankers[klass] = ranker
8
+ end
9
+
10
+ def self.set_default_position instance
11
+ if @rankers[instance.class] && @rankers[instance.class].strategy
12
+ position = instance.class.ranked.each_with_index { |record, index| break index if @rankers[instance.class].strategy.call(instance, record) } unless @rankers[instance.class].strategy.is_a?(Symbol)
13
+ end
14
+ position = instance.class.count - 1 if position.nil? || position.is_a?(Array)
15
+ instance.rank position
16
+ if @rankers[instance.class] && @rankers[instance.class].strategy.is_a?(Symbol)
17
+ instance.rank @rankers[instance.class].strategy, RankleIndex.where(indexable_name: @rankers[instance.class].strategy).count
18
+ end
19
+ end
20
+
21
+ def self.rank instance, name, position
22
+ rankle_index = RankleIndex.where(indexable_name: name.to_s, indexable_id: instance.id, indexable_type: instance.class).first_or_create!
23
+ rankle_index_length = if name == :default
24
+ RankleIndex.where(indexable_name: name.to_s, indexable_type: instance.class).count
25
+ else
26
+ RankleIndex.where(indexable_name: name.to_s).count
27
+ end
28
+ position = 0 if position < 0
29
+ position = rankle_index_length - 1 if position >= rankle_index_length
30
+ rankle_index.update_attribute(:indexable_position, rankle_index_length - 1) unless rankle_index.indexable_position
31
+ swap_distance = -1
32
+ swap_distance *= -1 if rankle_index.indexable_position < position
33
+ until rankle_index.indexable_position == position
34
+ if name == :default
35
+ swap(rankle_index, RankleIndex.where(indexable_name: name.to_s, indexable_type: instance.class, indexable_position: rankle_index.indexable_position + swap_distance).first)
36
+ else
37
+ swap(rankle_index, RankleIndex.where(indexable_name: name.to_s, indexable_position: rankle_index.indexable_position + swap_distance).first)
38
+ end
39
+ end
40
+ end
41
+
42
+ def self.position instance, name
43
+ where(indexable_name: name.to_s, indexable_id: instance.id, indexable_type: instance.class).first_or_create!.indexable_position
44
+ end
45
+
46
+ def self.ranked name
47
+ where(indexable_name: name).order(:indexable_position).map do |duck|
48
+ duck.indexable_type.classify.constantize.find(duck.indexable_id)
49
+ end
50
+ end
51
+
52
+ def self.swap(first_index, second_index)
53
+ first_index_position = first_index.indexable_position
54
+ first_index.update_attribute(:indexable_position, second_index.indexable_position)
55
+ second_index.update_attribute(:indexable_position, first_index_position)
56
+ end
57
+ end
data/rankle.gemspec CHANGED
@@ -21,7 +21,6 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency "activerecord"
22
22
  spec.add_development_dependency "bundler", "~> 1.7"
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
- spec.add_development_dependency "cucumber"
25
24
  spec.add_development_dependency "sqlite3"
26
25
  spec.add_development_dependency "rspec-expectations"
27
26
  spec.add_development_dependency "database_cleaner"
@@ -0,0 +1,22 @@
1
+ require_relative './support/test_helper'
2
+
3
+ class TestDefaultBehavior < Minitest::Test
4
+ def test_it_is_ineffectual
5
+ assert(Fruit.all.to_a == Fruit.ranked.to_a)
6
+ end
7
+
8
+ def test_it_sets_position
9
+ apple = Fruit.create!
10
+ orange = Fruit.create!
11
+
12
+ assert_equal 0, apple.position
13
+ assert_equal 1, orange.position
14
+ end
15
+
16
+ def test_it_ranks_on_insert_order
17
+ Fruit.create! name: 'apple'
18
+ Fruit.create! name: 'orange'
19
+
20
+ assert_equal ['apple', 'orange'], Fruit.ranked.map(&:name)
21
+ end
22
+ end
@@ -0,0 +1,70 @@
1
+ require_relative './support/test_helper'
2
+
3
+ class TestNamedRanking < Minitest::Test
4
+ def test_it_ranks_multiple_resources_together
5
+ apple = Fruit.create! name: 'apple'
6
+ carrot = Vegetable.create! name: 'carrot'
7
+
8
+ apple.rank :produce, 0
9
+ carrot.rank :produce, 1
10
+
11
+ assert_equal 0, apple.position
12
+ assert_equal 0, carrot.position
13
+
14
+ assert_equal 0, apple.position(:produce)
15
+ assert_equal 1, carrot.position(:produce)
16
+
17
+ assert_equal ['apple'], Fruit.ranked.map(&:name)
18
+ assert_equal ['carrot'], Vegetable.ranked.map(&:name)
19
+ end
20
+
21
+ def test_it_does_not_expand_scope
22
+ apple = Fruit.create! name: 'apple'
23
+ carrot = Vegetable.create! name: 'carrot'
24
+
25
+ apple.rank :produce, 0
26
+ carrot.rank :produce, 1
27
+
28
+ assert_equal 0, apple.position
29
+ assert_equal 0, carrot.position
30
+
31
+ assert_equal 0, apple.position(:produce)
32
+ assert_equal 1, carrot.position(:produce)
33
+
34
+ assert_equal ['apple'], Fruit.ranked(:produce).map(&:name)
35
+ assert_equal ['carrot'], Vegetable.ranked(:produce).map(&:name)
36
+ end
37
+
38
+ def test_it_can_access_the_global_scope
39
+ apple = Fruit.create! name: 'apple'
40
+ carrot = Vegetable.create! name: 'carrot'
41
+
42
+ apple.rank :produce, 0
43
+ carrot.rank :produce, 1
44
+
45
+ assert_equal 0, apple.position
46
+ assert_equal 0, carrot.position
47
+
48
+ assert_equal 0, apple.position(:produce)
49
+ assert_equal 1, carrot.position(:produce)
50
+
51
+ assert_equal ['apple', 'carrot'], Rankle.ranked(:produce).map(&:name)
52
+ end
53
+
54
+ def test_it_will_initialize_named_rankings_across_multiple_resources
55
+ Fruit.send :ranks, :produce
56
+ Vegetable.send :ranks, :produce
57
+
58
+ apple = Fruit.create! name: 'apple'
59
+ carrot = Vegetable.create! name: 'carrot'
60
+
61
+ assert_equal 0, apple.position
62
+ assert_equal 0, carrot.position
63
+
64
+ assert_equal 0, apple.position(:produce)
65
+ assert_equal 1, carrot.position(:produce)
66
+
67
+ # FIXME: This unfortunate hack reaches into the internals of RankleIndex to reset the test state
68
+ RankleIndex.instance_variable_set(:@rankers, {})
69
+ end
70
+ end
@@ -0,0 +1,75 @@
1
+ require_relative './support/test_helper'
2
+
3
+ class TestNamedRanking < Minitest::Test
4
+ def test_it_sets_the_position_for_the_named_ranking
5
+ apple = Fruit.create! name: 'apple'
6
+ orange = Fruit.create! name: 'orange'
7
+
8
+ apple.rank :reverse, 1
9
+ orange.rank :reverse, 0
10
+
11
+ assert_equal 0, apple.position
12
+ assert_equal 1, orange.position
13
+
14
+ assert_equal 1, apple.position(:reverse)
15
+ assert_equal 0, orange.position(:reverse)
16
+
17
+ assert_equal ['apple', 'orange'], Fruit.ranked.map(&:name)
18
+ assert_equal ['orange', 'apple'], Fruit.ranked(:reverse).map(&:name)
19
+ end
20
+
21
+ def test_it_does_not_initialize_named_rankings
22
+ apple = Fruit.create! name: 'apple'
23
+ banana = Fruit.create! name: 'banana'
24
+ orange = Fruit.create! name: 'orange'
25
+
26
+ apple.rank :reverse, 2
27
+ banana.rank :reverse, 1
28
+ orange.rank :reverse, 0
29
+
30
+ assert_equal 0, apple.position
31
+ assert_equal 1, banana.position
32
+ assert_equal 2, orange.position
33
+
34
+ assert_equal 1, apple.position(:reverse)
35
+ assert_equal 2, banana.position(:reverse)
36
+ assert_equal 0, orange.position(:reverse)
37
+
38
+ assert_equal ['apple', 'banana', 'orange'], Fruit.ranked.map(&:name)
39
+ assert_equal ['orange', 'apple', 'banana'], Fruit.ranked(:reverse).map(&:name)
40
+ end
41
+
42
+ def test_it_initializes_registered_named_rankings
43
+ Fruit.send :ranks, :reverse
44
+
45
+ apple = Fruit.create! name: 'apple'
46
+ banana = Fruit.create! name: 'banana'
47
+ orange = Fruit.create! name: 'orange'
48
+
49
+ assert_equal 0, apple.position
50
+ assert_equal 1, banana.position
51
+ assert_equal 2, orange.position
52
+
53
+ assert_equal 0, apple.position(:reverse)
54
+ assert_equal 1, banana.position(:reverse)
55
+ assert_equal 2, orange.position(:reverse)
56
+
57
+ apple.rank :reverse, 2
58
+ banana.rank :reverse, 1
59
+ orange.rank :reverse, 0
60
+
61
+ assert_equal 0, apple.position
62
+ assert_equal 1, banana.position
63
+ assert_equal 2, orange.position
64
+
65
+ assert_equal 2, apple.position(:reverse)
66
+ assert_equal 1, banana.position(:reverse)
67
+ assert_equal 0, orange.position(:reverse)
68
+
69
+ assert_equal ['apple', 'banana', 'orange'], Fruit.ranked.map(&:name)
70
+ assert_equal ['orange', 'banana', 'apple'], Fruit.ranked(:reverse).map(&:name)
71
+
72
+ # FIXME: This unfortunate hack reaches into the internals of RankleIndex to reset the test state
73
+ RankleIndex.instance_variable_set(:@rankers, {})
74
+ end
75
+ end
@@ -0,0 +1,14 @@
1
+ require_relative './support/test_helper'
2
+
3
+ class TestScopedRanking < Minitest::Test
4
+ def test_it_ranks_relative_to_a_scope
5
+ Fruit.class_exec { scope :berries, -> { where "name LIKE ?", '%berry' } }
6
+
7
+ ['apple', 'apricot', 'banana', 'bilberry', 'blackberry', 'blackcurrant', 'blueberry', 'boysenberry', 'cantaloupe'].each do |name|
8
+ Fruit.create! name: name
9
+ end
10
+
11
+ assert_equal ['apple', 'apricot', 'banana', 'bilberry', 'blackberry', 'blackcurrant', 'blueberry', 'boysenberry', 'cantaloupe'], Fruit.ranked.map(&:name)
12
+ assert_equal ['bilberry', 'blackberry', 'blueberry', 'boysenberry'], Fruit.berries.ranked.map(&:name)
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ require_relative './support/test_helper'
2
+
3
+ class TestSimpleUsage < Minitest::Test
4
+ def test_it_assigns_an_explicit_ranking
5
+ apple = Fruit.create! name: 'apple'
6
+ orange = Fruit.create! name: 'orange'
7
+
8
+ apple.update_attribute :position, 1
9
+
10
+ assert_equal 1, apple.position
11
+ assert_equal 0, orange.position
12
+
13
+ assert_equal ['orange', 'apple'], Fruit.ranked.map(&:name)
14
+ end
15
+
16
+ def test_it_sets_position_with_the_rank_method
17
+ apple = Fruit.create! name: 'apple'
18
+ orange = Fruit.create! name: 'orange'
19
+
20
+ apple.rank 1
21
+
22
+ assert_equal 1, apple.position
23
+ assert_equal 0, orange.position
24
+
25
+ assert_equal ['orange', 'apple'], Fruit.ranked.map(&:name)
26
+ end
27
+
28
+ def test_it_maintains_rank_with_a_proc
29
+ Fruit.send :ranks, ->(a, b) { a.name < b.name }
30
+
31
+ Fruit.create! name: 'apple'
32
+ Fruit.create! name: 'orange'
33
+ Fruit.create! name: 'banana'
34
+
35
+ assert_equal ['apple', 'banana', 'orange'], Fruit.ranked.map(&:name)
36
+
37
+ # FIXME: This unfortunate hack reaches into the internals of RankleIndex to reset the test state
38
+ RankleIndex.instance_variable_set(:@rankers, {})
39
+ end
40
+ end
@@ -0,0 +1,9 @@
1
+ #require_relative '../../lib/rankle_index'
2
+
3
+ class Fruit < ActiveRecord::Base
4
+ has_many :rankle_indices, as: :indexable
5
+ end
6
+
7
+ class Vegetable < ActiveRecord::Base
8
+ has_many :rankle_indices, as: :indexable
9
+ end
@@ -0,0 +1,15 @@
1
+ ActiveRecord::Schema.define do
2
+ self.verbose = false
3
+
4
+ create_table :fruits, :force => true do |t|
5
+ t.string :name
6
+
7
+ t.timestamps null: false
8
+ end
9
+
10
+ create_table :vegetables, :force => true do |t|
11
+ t.string :name
12
+
13
+ t.timestamps null: false
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/pride'
3
+ require 'rankle'
4
+ require 'database_cleaner'
5
+ require 'rails/generators'
6
+ require 'rake'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ adapter: 'sqlite3',
10
+ database: 'rankle.sqlite3'
11
+ )
12
+
13
+ rake = Rake.application
14
+ rake.init
15
+ rake.load_rakefile
16
+ Dir.entries(File.dirname(__FILE__) + '/../../db/migrate').each do |filename|
17
+ File.delete(File.dirname(__FILE__) + '/../../db/migrate/' + filename) rescue nil
18
+ end
19
+ Rails::Generators.invoke 'rankle:install'
20
+ require File.dirname(__FILE__) + '/../../db/migrate/' + Dir.entries(File.dirname(__FILE__) + '/../../db/migrate')[0]
21
+ File.delete 'rankle.sqlite3'
22
+ CreateRankleIndices.new.migrate :up
23
+
24
+ load File.dirname(__FILE__) + '/schema.rb'
25
+ load File.dirname(__FILE__) + '/models.rb'
26
+
27
+ DatabaseCleaner.strategy = :truncation
28
+
29
+ class Minitest::Test
30
+ def setup
31
+ DatabaseCleaner.start
32
+ end
33
+
34
+ def teardown
35
+ DatabaseCleaner.clean
36
+ end
37
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rankle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0.pre
4
+ version: 0.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wil
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-26 00:00:00.000000000 Z
11
+ date: 2015-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.0'
55
- - !ruby/object:Gem::Dependency
56
- name: cucumber
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: sqlite3
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -149,26 +135,21 @@ files:
149
135
  - LICENSE.txt
150
136
  - README.md
151
137
  - Rakefile
152
- - features/default_ranking.feature
153
- - features/get_position.feature
154
- - features/multi-resource_ranking.feature
155
- - features/named_ranking.feature
156
- - features/ranking.feature
157
- - features/set_position.feature
158
- - features/step_definitions/fruit_steps.rb
159
- - features/step_definitions/model_steps.rb
160
- - features/step_definitions/position_steps.rb
161
- - features/support/env.rb
162
- - features/support/factories/fruit.rb
163
- - features/support/factories/vegetable.rb
164
- - features/support/models.rb
165
- - features/support/schema.rb
166
138
  - lib/generators/rankle/install_generator.rb
167
139
  - lib/generators/rankle/templates/migration.rb
168
140
  - lib/rankle.rb
169
141
  - lib/rankle/ranker.rb
170
142
  - lib/rankle/version.rb
143
+ - lib/rankle_index.rb
171
144
  - rankle.gemspec
145
+ - test/default_behavior_test.rb
146
+ - test/multiple_resources_test.rb
147
+ - test/named_ranking_test.rb
148
+ - test/scoped_ranking_test.rb
149
+ - test/simple_usage_test.rb
150
+ - test/support/models.rb
151
+ - test/support/schema.rb
152
+ - test/support/test_helper.rb
172
153
  homepage: ''
173
154
  licenses:
174
155
  - MIT
@@ -184,9 +165,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
184
165
  version: '0'
185
166
  required_rubygems_version: !ruby/object:Gem::Requirement
186
167
  requirements:
187
- - - ">"
168
+ - - ">="
188
169
  - !ruby/object:Gem::Version
189
- version: 1.3.1
170
+ version: '0'
190
171
  requirements: []
191
172
  rubyforge_project:
192
173
  rubygems_version: 2.2.2
@@ -194,18 +175,12 @@ signing_key:
194
175
  specification_version: 4
195
176
  summary: Rankle provides multi-resource ranking.
196
177
  test_files:
197
- - features/default_ranking.feature
198
- - features/get_position.feature
199
- - features/multi-resource_ranking.feature
200
- - features/named_ranking.feature
201
- - features/ranking.feature
202
- - features/set_position.feature
203
- - features/step_definitions/fruit_steps.rb
204
- - features/step_definitions/model_steps.rb
205
- - features/step_definitions/position_steps.rb
206
- - features/support/env.rb
207
- - features/support/factories/fruit.rb
208
- - features/support/factories/vegetable.rb
209
- - features/support/models.rb
210
- - features/support/schema.rb
178
+ - test/default_behavior_test.rb
179
+ - test/multiple_resources_test.rb
180
+ - test/named_ranking_test.rb
181
+ - test/scoped_ranking_test.rb
182
+ - test/simple_usage_test.rb
183
+ - test/support/models.rb
184
+ - test/support/schema.rb
185
+ - test/support/test_helper.rb
211
186
  has_rdoc:
@@ -1,20 +0,0 @@
1
- Feature: Default ranking
2
- In order to not surprise new customers
3
- As a consumer of rankle
4
- I want the default behavior to match existing behavior
5
-
6
- Scenario: Empty fruit model
7
- Given an empty fruit model
8
- Then ranking all has no effect
9
- And the ranked fruit array is []
10
-
11
- Scenario: Fruit model with several fruits
12
- Given several fruits
13
- Then ranking all has no effect
14
- And the ranked fruit array is [Apple, Apricot, Banana, Bilberry, Blackberry, Blackcurrant, Blueberry, Boysenberry, Cantaloupe, Currant]
15
-
16
- Scenario: Ranked fruit
17
- Given an empty fruit model
18
- And an apple
19
- And an orange
20
- Then the ranked fruit array is [apple, orange]
@@ -1,19 +0,0 @@
1
- Feature: Get position
2
- In order to inspect a ranking
3
- As a developer
4
- I want to retrieve an element's position
5
-
6
- Scenario: Default ranking
7
- Given an apple
8
- And an orange
9
- Then the apple is in position 0
10
- And the orange is in position 1
11
- And the ranked fruit array is [apple, orange]
12
-
13
- Scenario: Custom ranking
14
- Given an apple
15
- And an orange
16
- When I assign the apple's position to 1
17
- Then the apple is in position 1
18
- And the orange is in position 0
19
- And the ranked fruit array is [orange, apple]
@@ -1,37 +0,0 @@
1
- Feature: Multi-resource ranking
2
- In order to rank multiple resources
3
- As a consumer of rankle
4
- I want to create a multi-resource ranking
5
-
6
- Scenario: Basic ranking
7
- Given a 'fruit' model
8
- And a 'vegetable' model
9
- And an 'apple' fruit
10
- And a 'carrot' vegetable
11
- When I assign the 'apple' fruit's 'produce' rank to '0'
12
- And I assign the 'carrot' vegetable's 'produce' rank to '1'
13
- Then the 'apple' fruit's 'default' rank is '0'
14
- And the 'carrot' vegetable's 'default' rank is '0'
15
- And the 'apple' fruit's 'produce' rank is '0'
16
- And the 'carrot' vegetable's 'produce' rank is '1'
17
- And the default ranked fruit array is [apple]
18
- And the default ranked vegetable array is [carrot]
19
- And the produce ranked fruit array is [apple]
20
- And the produce ranked vegetable array is [carrot]
21
- And the produce ranked rankle array is [apple, carrot]
22
-
23
-
24
- Scenario: Default ranking
25
- Given a 'fruit' model with a 'produce' ranking
26
- And a 'vegetable' model with a 'produce' ranking
27
- And an 'apple' fruit
28
- And a 'carrot' vegetable
29
- Then the 'apple' fruit's 'default' rank is '0'
30
- And the 'carrot' vegetable's 'default' rank is '0'
31
- And the 'apple' fruit's 'produce' rank is '0'
32
- And the 'carrot' vegetable's 'produce' rank is '1'
33
- And the default ranked fruit array is [apple]
34
- And the default ranked vegetable array is [carrot]
35
- And the produce ranked fruit array is [apple]
36
- And the produce ranked vegetable array is [carrot]
37
- And the produce ranked rankle array is [apple, carrot]
@@ -1,49 +0,0 @@
1
- Feature: Named ranking
2
- In order to maintain multiple rankings on a single class
3
- As a developer
4
- I want to create named rankings
5
-
6
- Scenario: Reverse ranking
7
- Given an apple
8
- And an orange
9
- When I assign the 'apple' fruit's 'reverse' rank to '1'
10
- When I assign the 'orange' fruit's 'reverse' rank to '0'
11
- Then the 'apple' fruit's 'default' rank is '0'
12
- And the 'orange' fruit's 'default' rank is '1'
13
- And the 'apple' fruit's 'reverse' rank is '1'
14
- And the 'orange' fruit's 'reverse' rank is '0'
15
- And the default ranked fruit array is [apple, orange]
16
- And the reverse ranked fruit array is [orange, apple]
17
-
18
- Scenario: Growing ranking
19
- Given an apple
20
- And a banana
21
- And an orange
22
- When I assign the 'apple' fruit's 'reverse' rank to '2'
23
- And I assign the 'banana' fruit's 'reverse' rank to '1'
24
- And I assign the 'orange' fruit's 'reverse' rank to '0'
25
- Then the 'apple' fruit's 'default' rank is '0'
26
- And the 'banana' fruit's 'default' rank is '1'
27
- And the 'orange' fruit's 'default' rank is '2'
28
- And the 'apple' fruit's 'reverse' rank is '1'
29
- And the 'banana' fruit's 'reverse' rank is '2'
30
- And the 'orange' fruit's 'reverse' rank is '0'
31
- And the default ranked fruit array is [apple, banana, orange]
32
- And the reverse ranked fruit array is [orange, apple, banana]
33
-
34
- Scenario: Registered ranking
35
- Given a 'fruit' class with a 'reverse' ranking
36
- And an apple
37
- And a banana
38
- And an orange
39
- When I assign the 'apple' fruit's 'reverse' rank to '2'
40
- And I assign the 'banana' fruit's 'reverse' rank to '1'
41
- And I assign the 'orange' fruit's 'reverse' rank to '0'
42
- Then the 'apple' fruit's 'default' rank is '0'
43
- And the 'banana' fruit's 'default' rank is '1'
44
- And the 'orange' fruit's 'default' rank is '2'
45
- And the 'apple' fruit's 'reverse' rank is '2'
46
- And the 'banana' fruit's 'reverse' rank is '1'
47
- And the 'orange' fruit's 'reverse' rank is '0'
48
- And the default ranked fruit array is [apple, banana, orange]
49
- And the reverse ranked fruit array is [orange, banana, apple]
@@ -1,24 +0,0 @@
1
- Feature: Ranks
2
- In order to provide an explicit ordering
3
- As a developer
4
- I want to rank on position
5
-
6
- Scenario: Reverse ranking
7
- Given 10 rows
8
- When I rank them in reverse order
9
- Then ranking is equivalent to all reversed
10
-
11
- Scenario: Update ranking
12
- Given 10 rows in default order
13
- When I move row 9 to row 0
14
- Then ranking is equivalent to all rotated -1
15
-
16
- Scenario: Negative rank
17
- Given 10 rows in default order
18
- When I move row 9 to row -10
19
- Then row 9 is in position 0
20
-
21
- Scenario: Out-of-bounds rank
22
- Given 10 rows in default order
23
- When I move row 0 to row 30
24
- Then row 0 is in position 9
@@ -1,41 +0,0 @@
1
- Feature: Set position
2
- In order to assign a ranking
3
- As a developer
4
- I want to set an element's position
5
-
6
- Scenario: Update position attribute
7
- Given an empty fruit model
8
- And an 'apple' fruit
9
- And an 'orange' fruit
10
- When I update the apple's position attribute to 1
11
- Then the apple is in position 1
12
- And the orange is in position 0
13
- Then the ranked fruit array is [orange, apple]
14
-
15
- Scenario: Update position attribute with rank method
16
- Given an apple
17
- And an orange
18
- When I assign the apple's rank to 1
19
- Then the apple is in position 1
20
- And the orange is in position 0
21
- Then the ranked fruit array is [orange, apple]
22
-
23
-
24
- Scenario: Override default with stabby proc
25
- Given a fruit class with a reverse alphabetical default ranking on name
26
- And an apple
27
- And an orange
28
- Then the apple is in position 1
29
- And the orange is in position 0
30
- Then the ranked fruit array is [orange, apple]
31
-
32
-
33
- Scenario: Override default with stabby proc (documentation)
34
- Given a fruit class with an alphabetical default ranking on name
35
- And an apple
36
- And an orange
37
- And a banana
38
- Then the apple is in position 0
39
- And the banana is in position 1
40
- And the orange is in position 2
41
- Then the ranked fruit array is [apple, banana, orange]
@@ -1,29 +0,0 @@
1
- Given(/^an apple$/) do
2
- DatabaseCleaner.clean
3
- @fruit ||= {}
4
- @fruit[:apple] = create :fruit, name: 'apple'
5
- end
6
-
7
- Given(/^an orange$/) do
8
- @fruit[:orange] = create :fruit, name: 'orange'
9
- end
10
-
11
- Given(/^a banana$/) do
12
- @fruit[:banana] = create :fruit, name: 'banana'
13
- end
14
-
15
- Then(/^the apple is in position (\d+)$/) do |position|
16
- expect(@fruit[:apple].position).to eq(position.to_i)
17
- end
18
-
19
- Then(/^the orange is in position (\d+)$/) do |position|
20
- expect(@fruit[:orange].position).to eq(position.to_i)
21
- end
22
-
23
- Then(/^the banana is in position (\d+)$/) do |position|
24
- expect(@fruit[:banana].position).to eq(position.to_i)
25
- end
26
-
27
- When(/^I assign the apple's position to (\d+)$/) do |position|
28
- @fruit[:apple].update_attribute(:position, position.to_i)
29
- end
@@ -1,101 +0,0 @@
1
- Given(/^a '(.*)' model$/) do |name|
2
- DatabaseCleaner.clean
3
- name.classify.constantize.delete_all
4
- end
5
-
6
- Given(/^a '(.*)' model with a '(.*)' ranking$/) do |klass, ranking|
7
- step "a '#{klass}' model"
8
- klass.classify.constantize.send :ranks, ranking.to_sym
9
- end
10
-
11
-
12
- Given(/^an '(.*)' fruit$/) do |name|
13
- @fruit ||= {}
14
- @fruit[name.to_sym] = create :fruit, name: name
15
- end
16
-
17
- Given(/^a '(.*)' vegetable$/) do |name|
18
- @vegetable ||= {}
19
- @vegetable[name.to_sym] = create :vegetable, name: name
20
- end
21
-
22
- Given(/^an empty (.+) model$/) do |klass|
23
- DatabaseCleaner.clean
24
- klass.classify.constantize.delete_all
25
- end
26
-
27
- Given(/^several fruits$/) do
28
- DatabaseCleaner.clean
29
- @fruit ||= {}
30
- 10.times.each do |index|
31
- fruit = create :fruit
32
- @fruit[fruit.name.to_sym] = fruit
33
- end
34
- end
35
-
36
- Given(/^several points$/) do
37
- DatabaseCleaner.clean
38
- 10.times.each { |index| Point.create!(x: index, y: index) }
39
- end
40
-
41
- Given(/^(\d+) rows$/) do |count|
42
- DatabaseCleaner.clean
43
- count.to_i.times.each { |index| Row.create!(text: index) }
44
- end
45
-
46
- Given(/^(\d+) rows in default order$/) do |count|
47
- DatabaseCleaner.clean
48
- count.to_i.times.each { |index| Row.create!(text: index).update_attribute(:position, index) }
49
- end
50
-
51
- Given(/^(\d+) even and odd rows$/) do |count|
52
- DatabaseCleaner.clean
53
- count.to_i.times.each { |index| Row.create!(text: index.even? ? 'even' : 'odd').update_attribute(:position, index) }
54
- end
55
-
56
- When(/^I rank them in reverse order$/) do
57
- Row.all.reverse.each_with_index { |row, index| row.update_attribute(:position, index) }
58
- end
59
-
60
- When(/^I move row (\d+) to row (-?\d+)$/) do |start_position, end_position|
61
- Row.all[start_position.to_i].update_attribute(:position, end_position.to_i)
62
- end
63
-
64
- When(/^I reverse rank the even rows$/) do
65
- Row.rank(:even)
66
- end
67
-
68
- Then(/^ranking is equivalent to all reversed$/) do
69
- expect(Row.ranked.to_a).to eq(Row.all.to_a.reverse)
70
- end
71
-
72
- Then(/^ranking is equivalent to all rotated (\-\d+)$/) do |positions|
73
- expect(Row.ranked.to_a).to eq(Row.all.to_a.rotate(positions.to_i))
74
- end
75
-
76
- Then(/^ranking all has no effect$/) do
77
- expect(Point.ranked.to_a).to eq(Point.all.to_a)
78
- end
79
-
80
- Then(/^row (\d+) is in position (\d+)$/) do |row, position|
81
- expect(Row.ranked[position.to_i].id).to eq(row.to_i + 1)
82
- end
83
-
84
- Given(/^a fruit class with an alphabetical default ranking on name$/) do
85
- Fruit.send :ranks, ->(a, b) { a.name < b.name }
86
- end
87
-
88
- Given(/^a fruit class with a reverse alphabetical default ranking on name$/) do
89
- Fruit.send :ranks, ->(a, b) { a.name > b.name }
90
- end
91
-
92
- Given(/^a 'fruit' class with a 'reverse' ranking$/) do
93
- Fruit.send :ranks, :reverse
94
- end
95
-
96
- Then(/^the (.*)ranked (.*) array is \[(.*)\]$/) do |ranker, klass, names|
97
- ranker = 'default' if ranker.blank?
98
- expect(klass.classify.constantize.ranked(ranker.strip.to_sym).map(&:name)).to eq(names.split(',').map do |name|
99
- @fruit[name.strip.to_sym].name rescue @vegetable[name.strip.to_sym].name
100
- end)
101
- end
@@ -1,24 +0,0 @@
1
- When(/^I update the apple's position attribute to (\d+)$/) do |position|
2
- @fruit[:apple].update_attribute(:position, position.to_i)
3
- end
4
-
5
- When(/^I assign the apple's rank to (\d+)$/) do |position|
6
- @fruit[:apple].rank position.to_i
7
- end
8
-
9
- When(/^I assign the '(.*)' fruit's '(.*)' rank to '(\d+)'$/) do |type, name, position|
10
- @fruit[type.to_sym].rank name.to_sym, position.to_i
11
- end
12
-
13
- When(/^I assign the '(.*)' vegetable's '(.*)' rank to '(\d+)'$/) do |type, name, position|
14
- @vegetable[type.to_sym].rank name.to_sym, position.to_i
15
- end
16
-
17
-
18
- Then(/^the '(.*)' fruit's '(.*)' rank is '(\d+)'$/) do |type, name, position|
19
- expect(@fruit[type.to_sym].position name).to eq(position.to_i)
20
- end
21
-
22
- Then(/^the '(.*)' vegetable's '(.*)' rank is '(\d+)'$/) do |type, name, position|
23
- expect(@vegetable[type.to_sym].position name).to eq(position.to_i)
24
- end
@@ -1,15 +0,0 @@
1
- require 'rankle'
2
- require 'database_cleaner'
3
- require 'factory_girl'
4
-
5
- DatabaseCleaner.strategy = :truncation
6
-
7
- ActiveRecord::Base.establish_connection(
8
- adapter: 'sqlite3',
9
- database: 'rankle.sqlite3'
10
- )
11
-
12
- load File.dirname(__FILE__) + '/schema.rb'
13
- load File.dirname(__FILE__) + '/models.rb'
14
-
15
- World FactoryGirl::Syntax::Methods
@@ -1,16 +0,0 @@
1
- FactoryGirl.define do
2
- factory :fruit do
3
- sequence(:name) { |n| FRUITS[n-1] }
4
- end
5
- end
6
-
7
- FRUITS = ['Apple', 'Apricot', 'Banana', 'Bilberry', 'Blackberry', 'Blackcurrant', 'Blueberry', 'Boysenberry',
8
- 'Cantaloupe', 'Currant', 'Cherry', 'Cherimoya', 'Cloudberry', 'Coconut', 'Cranberry', 'Damson', 'Date',
9
- 'Dragonfruit', 'Durian', 'Elderberry', 'Feijoa', 'Fig', 'Goji berry', 'Gooseberry', 'Grape', 'Raisin',
10
- 'Grapefruit', 'Guava', 'Huckleberry', 'Jackfruit', 'Jambul', 'Jujube', 'Kiwi fruit', 'Kumquat', 'Lemon',
11
- 'Lime', 'Loquat', 'Lychee', 'Mango', 'Marion berry', 'Melon', 'Cantaloupe', 'Honeydew', 'Watermelon',
12
- 'Rock melon', 'Miracle fruit', 'Mulberry', 'Nectarine', 'Olive', 'Orange', 'Clementine', 'Mandarine',
13
- 'Tangerine', 'Papaya', 'Passionfruit', 'Peach', 'Pear', 'Williams pear', 'Bartlett pear', 'Persimmon',
14
- 'Physalis', 'Plum/prune (dried plum)', 'Pineapple', 'Pomegranate', 'Pomelo', 'Purple Mangosteen', 'Quince',
15
- 'Raspberry', 'Salmon berry', 'Black raspberry', 'Rambutan', 'Redcurrant', 'Salal berry', 'Satsuma',
16
- 'Star fruit', 'Strawberry', 'Tamarillo', 'Ugli fruit']
@@ -1,36 +0,0 @@
1
- FactoryGirl.define do
2
- factory :vegetable do
3
- sequence(:name) { |n| VEGETABLES[n-1] }
4
- end
5
-
6
- #factory :legume, class: Vegetable do
7
- # sequence(:name) { |n| LEGUMES[n-1] }
8
- #end
9
- end
10
-
11
- VEGETABLES = ['Artichoke', 'Arugula', 'Asparagus', 'Amaranth', 'Bok choy', 'Broccoflower', 'Broccoli',
12
- 'Brussels sprouts', 'Cabbage', 'Calabrese', 'Cannabis', 'Carrots', 'Cauliflower', 'Celery', 'Chard',
13
- 'Collard greens', 'Corn salad', 'Eggplant', 'Endive', 'Fiddleheads', 'Frisee', 'Kale', 'Kohlrabi',
14
- 'Lettuce Lactuca sativa', 'Corn', 'Mushrooms', 'Mustard greens', 'Nettles', 'New Zealand spinach', 'Okra',
15
- 'Parsley', 'Radicchio', 'Rhubarb', 'Salsify', 'Skirret', 'Spinach', 'Topinambur', 'Tat soi', 'Tomato',
16
- 'Water chestnut', 'Watercress']
17
-
18
- LEGUMES = ['Alfalfa sprouts', 'Azuki beans', 'Bean sprouts', 'Black beans', 'Black-eyed peas', 'Borlotti bean',
19
- 'Broad beans', 'Chickpeas', 'Green beans', 'Kidney beans', 'Lentils', 'Lima beans', 'Mung beans',
20
- 'Navy beans', 'Pinto beans', 'Runner beans', 'Soy beans', 'Snap peas']
21
-
22
- HERBS_AND_SPICES = ['Anise', 'Basil', 'Caraway', 'Cilantro', 'Coriander', 'Chamomile', 'Dill', 'Fennel', 'Lavender',
23
- 'Lemon Grass', 'Marjoram', 'Oregano', 'Parsley', 'Rosemary', 'Sage', 'Thyme']
24
-
25
- ONIONS = ['Chives', 'Garlic', 'Leek Allium porrum', 'Onion', 'Shallot', 'Scallion']
26
-
27
- PEPPERS = ['Bell pepper', 'Chili pepper', 'Jalapeno', 'Habanero', 'Paprika', 'Tabasco pepper', 'Cayenne pepper']
28
-
29
- ROOT_VEGETABLES = ['Beet', 'Carrot', 'Celeriac', 'Daikon', 'Ginger', 'Parsnip', 'Rutabaga', 'Turnip']
30
-
31
- RADISH = ['Rutabaga', 'Turnip', 'Wasabi', 'Horseradish', 'White radish']
32
-
33
- SQUASHES = ['Acorn squash', 'Butternut squash', 'Banana squash', 'Zucchini', 'Cucumber', 'Delicata', 'Gem squash',
34
- 'Hubbard squash', 'Squash', 'Patty pans', 'Pumpkin', 'Spaghetti squash']
35
-
36
- TUBERS = ['Jicama', 'Jerusalem artichoke', 'Potato', 'Sweet potato', 'Taro', 'Yam']
@@ -1,19 +0,0 @@
1
- class RankleIndex < ActiveRecord::Base
2
- belongs_to :indexable, polymorphic: true
3
- end
4
-
5
- class Fruit < ActiveRecord::Base
6
- has_many :rankle_indices, as: :indexable
7
- end
8
-
9
- class Vegetable < ActiveRecord::Base
10
- has_many :rankle_indices, as: :indexable
11
- end
12
-
13
- class Point < ActiveRecord::Base
14
- has_many :rankle_indices, as: :indexable
15
- end
16
-
17
- class Row < ActiveRecord::Base
18
- has_many :rankle_indices, as: :indexable
19
- end
@@ -1,37 +0,0 @@
1
- ActiveRecord::Schema.define do
2
- self.verbose = false
3
-
4
- create_table :fruits, :force => true do |t|
5
- t.string :name
6
-
7
- t.timestamps null: false
8
- end
9
-
10
- create_table :vegetables, :force => true do |t|
11
- t.string :name
12
-
13
- t.timestamps null: false
14
- end
15
-
16
- create_table :points, :force => true do |t|
17
- t.integer :x
18
- t.integer :y
19
-
20
- t.timestamps null: false
21
- end
22
-
23
- create_table :rows, :force => true do |t|
24
- t.string :text
25
-
26
- t.timestamps null: false
27
- end
28
-
29
- create_table :rankle_indices, :force => true do |t|
30
- t.string :indexable_name
31
- t.integer :indexable_id
32
- t.string :indexable_type
33
- t.integer :indexable_position
34
-
35
- t.timestamps null: false
36
- end
37
- end