forked from OpenNeo/impress
basic specs for items, including search
This commit is contained in:
parent
fb73d23db8
commit
851aa49091
9 changed files with 301 additions and 4 deletions
|
@ -1,3 +1,64 @@
|
|||
class Item
|
||||
class Item < ActiveRecord::Base
|
||||
set_table_name 'objects' # Neo & PHP Impress call them objects, but the class name is a conflict (duh!)
|
||||
set_inheritance_column 'inheritance_type' # PHP Impress used "type" to describe category
|
||||
|
||||
# Not defining validations, since this app is currently read-only
|
||||
|
||||
def species_support_ids
|
||||
@species_support_ids_array ||= read_attribute('species_support_ids').split(',').map(&:to_i)
|
||||
end
|
||||
|
||||
def species_support_ids=(replacement)
|
||||
replacement = replacement.join(',') if replacement.is_a?(Array)
|
||||
write_attribute('species_support_ids', replacement)
|
||||
end
|
||||
|
||||
def self.search(query)
|
||||
query_conditions = [Condition.new]
|
||||
in_phrase = false
|
||||
query.each_char do |c|
|
||||
if c == ' ' && !in_phrase
|
||||
query_conditions << Condition.new
|
||||
elsif c == '"'
|
||||
in_phrase = !in_phrase
|
||||
elsif c == ':' && !in_phrase
|
||||
query_conditions.last.to_property!
|
||||
else
|
||||
query_conditions.last << c
|
||||
end
|
||||
end
|
||||
query_conditions.inject(self) do |scope, condition|
|
||||
condition.narrow(scope)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
class Condition < String
|
||||
attr_reader :property
|
||||
|
||||
def to_property!
|
||||
@property = self.clone
|
||||
self.replace ''
|
||||
end
|
||||
|
||||
def narrow(scope)
|
||||
if @property == 'species'
|
||||
species = Species.find_by_name(self)
|
||||
# TODO: add a many-to-many table to handle this relationship
|
||||
scope.where('species_support_ids = ? OR species_support_ids LIKE ? OR species_support_ids LIKE ? OR species_support_ids LIKE ?',
|
||||
species.id,
|
||||
"#{species.id},%",
|
||||
"%,#{species.id},%",
|
||||
"%,#{species.id}"
|
||||
)
|
||||
else
|
||||
scope.where('name LIKE :matcher OR description LIKE :matcher', :matcher => "%#{self}%")
|
||||
end
|
||||
end
|
||||
|
||||
def inspect
|
||||
@property ? "#{@property}:#{super}" : super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
20
app/models/species.rb
Normal file
20
app/models/species.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
class Species
|
||||
attr_accessor :id, :name
|
||||
|
||||
@objects = []
|
||||
@objects_by_name = {}
|
||||
File.open(Rails.root.join('config', 'species.txt')).each do |line|
|
||||
name = line.chomp.downcase
|
||||
@objects << @objects_by_name[name] = species = Species.new
|
||||
species.id = @objects.size
|
||||
species.name = name
|
||||
end
|
||||
|
||||
def self.find(id)
|
||||
@objects[id-1]
|
||||
end
|
||||
|
||||
def self.find_by_name(name)
|
||||
@objects_by_name[name.downcase]
|
||||
end
|
||||
end
|
54
config/species.txt
Normal file
54
config/species.txt
Normal file
|
@ -0,0 +1,54 @@
|
|||
Acara
|
||||
Aisha
|
||||
Blumaroo
|
||||
Bori
|
||||
Bruce
|
||||
Buzz
|
||||
Chia
|
||||
Chomby
|
||||
Cybunny
|
||||
Draik
|
||||
Elephante
|
||||
Eyrie
|
||||
Flotsam
|
||||
Gelert
|
||||
Gnorbu
|
||||
Grarrl
|
||||
Grundo
|
||||
Hissi
|
||||
Ixi
|
||||
Jetsam
|
||||
Jubjub
|
||||
Kacheek
|
||||
Kau
|
||||
Kiko
|
||||
Koi
|
||||
Korbat
|
||||
Kougra
|
||||
Krawk
|
||||
Kyrii
|
||||
Lenny
|
||||
Lupe
|
||||
Lutari
|
||||
Meerca
|
||||
Moehog
|
||||
Mynci
|
||||
Nimmo
|
||||
Ogrin
|
||||
Peophin
|
||||
Poogle
|
||||
Pteri
|
||||
Quiggle
|
||||
Ruki
|
||||
Scorchio
|
||||
Shoyru
|
||||
Skeith
|
||||
Techo
|
||||
Tonu
|
||||
Tuskaninny
|
||||
Uni
|
||||
Usul
|
||||
Wocky
|
||||
Xweetok
|
||||
Yurble
|
||||
Zafara
|
|
@ -1,6 +1,6 @@
|
|||
class CreateItems < ActiveRecord::Migration
|
||||
class CreateObjects < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :items do |t|
|
||||
create_table :objects do |t|
|
||||
t.string :name
|
||||
t.string :species_support_ids
|
||||
|
||||
|
@ -9,6 +9,6 @@ class CreateItems < ActiveRecord::Migration
|
|||
end
|
||||
|
||||
def self.down
|
||||
drop_table :items
|
||||
drop_table :objects
|
||||
end
|
||||
end
|
9
db/migrate/20100515020945_add_description_to_objects.rb
Normal file
9
db/migrate/20100515020945_add_description_to_objects.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
class AddDescriptionToObjects < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :objects, :description, :text
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :objects, :description
|
||||
end
|
||||
end
|
22
db/schema.rb
Normal file
22
db/schema.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
# This file is auto-generated from the current state of the database. Instead of editing this file,
|
||||
# please use the migrations feature of Active Record to incrementally modify your database, and
|
||||
# then regenerate this schema definition.
|
||||
#
|
||||
# Note that this schema.rb definition is the authoritative source for your database schema. If you need
|
||||
# to create the application database on another system, you should be using db:schema:load, not running
|
||||
# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
||||
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20100515020945) do
|
||||
|
||||
create_table "objects", :force => true do |t|
|
||||
t.string "name"
|
||||
t.string "species_support_ids"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.text "description"
|
||||
end
|
||||
|
||||
end
|
105
spec/models/item_spec.rb
Normal file
105
spec/models/item_spec.rb
Normal file
|
@ -0,0 +1,105 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Item do
|
||||
specify "should accept string or array for species_support_ids" do
|
||||
items = [
|
||||
Factory.build(:item, :species_support_ids => '1,2,3'),
|
||||
Factory.build(:item, :species_support_ids => [1,2,3])
|
||||
]
|
||||
items.each { |i| i.species_support_ids.should == [1,2,3] }
|
||||
end
|
||||
|
||||
specify "class should search name for word" do
|
||||
query_should 'blue',
|
||||
:return => [
|
||||
'A Hat That is Blue',
|
||||
'Blue Hat',
|
||||
'Blueish Hat',
|
||||
'Very Blue Hat'
|
||||
],
|
||||
:not_return => [
|
||||
'Green Hat',
|
||||
'Red Hat'
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search name for phrase" do
|
||||
query_should '"one two"',
|
||||
:return => [
|
||||
'Zero one two three',
|
||||
'Zero one two',
|
||||
'One two three'
|
||||
],
|
||||
:not_return => [
|
||||
'Zero one three',
|
||||
'Zero two three',
|
||||
'Zero one and two',
|
||||
'Three two one'
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search name for multiple words" do
|
||||
query_should 'one two',
|
||||
:return => [
|
||||
'Zero one two three',
|
||||
'Zero one two',
|
||||
'One two three',
|
||||
'Zero one and two',
|
||||
'Three two one'
|
||||
],
|
||||
:not_return => [
|
||||
'Zero one three',
|
||||
'Zero two three'
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search name for words and phrases" do
|
||||
query_should 'zero "one two" three',
|
||||
:return => [
|
||||
'zero one two three',
|
||||
'zero four one two three',
|
||||
'one two zero three',
|
||||
'three zero one two'
|
||||
],
|
||||
:not_return => [
|
||||
'one two three',
|
||||
'zero one two',
|
||||
'three one zero two',
|
||||
'two one three zero'
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search name and description" do
|
||||
query_should 'zero "one two"',
|
||||
:return => [
|
||||
'zero one two',
|
||||
['zero one', 'one two three'],
|
||||
['one two four', 'one three zero'],
|
||||
['three', 'one two four zero']
|
||||
],
|
||||
:not_return => [
|
||||
['zero one', 'two'],
|
||||
['one two four', 'three'],
|
||||
['five two', 'zero one three two']
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search by species" do
|
||||
[[2],[1,2,3],[2,3],[3],[1,3]].each do |ids|
|
||||
Factory.create :item, :species_support_ids => ids
|
||||
end
|
||||
Item.search('species:acara').count.should == 2
|
||||
Item.search('species:aisha').count.should == 3
|
||||
Item.search('species:blumaroo').count.should == 4
|
||||
end
|
||||
|
||||
specify "class should search by species and words" do
|
||||
Factory.create :item, :name => 'Blue Hat', :species_support_ids => [1]
|
||||
Factory.create :item, :name => 'Very Blue Hat', :species_support_ids => [1,2]
|
||||
Factory.create :item, :name => 'Red Hat', :species_support_ids => [2]
|
||||
Item.search('blue species:acara').count.should == 2
|
||||
Item.search('blue species:aisha').count.should == 1
|
||||
Item.search('red species:acara').count.should == 0
|
||||
Item.search('red species:aisha').count.should == 1
|
||||
end
|
||||
end
|
18
spec/models/species_spec.rb
Normal file
18
spec/models/species_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Species do
|
||||
specify "should find by id, report name" do
|
||||
Species.find(1).name.should == 'acara'
|
||||
Species.find(2).name.should == 'aisha'
|
||||
end
|
||||
|
||||
specify "should find by name, report id" do
|
||||
Species.find_by_name('acara').id.should == 1
|
||||
Species.find_by_name('aisha').id.should == 2
|
||||
end
|
||||
|
||||
specify "name should be case-insensitive" do
|
||||
Species.find_by_name('Acara').id.should == 1
|
||||
Species.find_by_name('acara').id.should == 1
|
||||
end
|
||||
end
|
|
@ -21,4 +21,12 @@ Rspec.configure do |config|
|
|||
# If you'd prefer not to run each of your examples within a transaction,
|
||||
# uncomment the following line.
|
||||
# config.use_transactional_examples = false
|
||||
|
||||
def query_should(query, sets)
|
||||
sets = sets.each { |k,v| sets[k] = v.map { |x| x.is_a?(Array) ? x : [x, ''] } }
|
||||
all_sets = sets[:return] + sets[:not_return]
|
||||
all_sets.each { |s| Factory.create :item, :name => s[0], :description => s[1]}
|
||||
returned_sets = Item.search(query).all.map { |i| [i.name, i.description] }.sort
|
||||
returned_sets.should == sets[:return].sort
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue