meta_search 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +101 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/meta_search/builder.rb +247 -0
- data/lib/meta_search/exceptions.rb +3 -0
- data/lib/meta_search/helpers/action_view.rb +168 -0
- data/lib/meta_search/model_compatibility.rb +8 -0
- data/lib/meta_search/railtie.rb +21 -0
- data/lib/meta_search/searches/active_record.rb +19 -0
- data/lib/meta_search/searches/base.rb +46 -0
- data/lib/meta_search/utility.rb +85 -0
- data/lib/meta_search/where.rb +174 -0
- data/lib/meta_search.rb +31 -0
- data/meta_search.gemspec +83 -0
- data/test/fixtures/companies.yml +17 -0
- data/test/fixtures/company.rb +9 -0
- data/test/fixtures/data_type.rb +4 -0
- data/test/fixtures/data_types.yml +15 -0
- data/test/fixtures/developer.rb +5 -0
- data/test/fixtures/developers.yml +55 -0
- data/test/fixtures/developers_projects.yml +25 -0
- data/test/fixtures/note.rb +3 -0
- data/test/fixtures/notes.yml +79 -0
- data/test/fixtures/project.rb +4 -0
- data/test/fixtures/projects.yml +24 -0
- data/test/fixtures/schema.rb +47 -0
- data/test/helper.rb +37 -0
- data/test/test_search.rb +351 -0
- data/test/test_view_helpers.rb +149 -0
- metadata +116 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'meta_search/builder'
|
2
|
+
|
3
|
+
module MetaSearch
|
4
|
+
module Searches
|
5
|
+
module Base
|
6
|
+
# Prepares the search to run against your model. Returns an instance of
|
7
|
+
# MetaSearch::Builder, which behaves pretty much like an ActiveRecord::Relation,
|
8
|
+
# in that it doesn't actually query the database until you do something that
|
9
|
+
# requires it to do so.
|
10
|
+
def search(opts = {})
|
11
|
+
opts ||= {} # to catch nil params
|
12
|
+
search_options = opts.delete(:search_options) || {}
|
13
|
+
builder = MetaSearch::Builder.new(self, search_options)
|
14
|
+
builder.build(opts)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Excludes model attributes from searchability. This means that searches can't be created against
|
20
|
+
# these columns, whether the search is based on this model, or the model's attributes are being
|
21
|
+
# searched by association from another model. If a Comment <tt>belongs_to :article</tt> but declares
|
22
|
+
# <tt>metasearch_exclude_attr :user_id</tt> then <tt>Comment.search</tt> won't accept parameters
|
23
|
+
# like <tt>:user_id_equals</tt>, nor will an Article.search accept the parameter
|
24
|
+
# <tt>:comments_user_id_equals</tt>.
|
25
|
+
def metasearch_exclude_attr(*args)
|
26
|
+
args.each do |attr|
|
27
|
+
attr = attr.to_s
|
28
|
+
raise(ArgumentError, "No persisted attribute (column) named #{attr} in #{self}") unless self.columns_hash.has_key?(attr)
|
29
|
+
self._metasearch_exclude_attributes = (self._metasearch_exclude_attributes + [attr]).uniq
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Excludes model associations from searchability. This mean that searches can't be created against
|
34
|
+
# these associations. An article that <tt>has_many :comments</tt> but excludes comments from
|
35
|
+
# searching by declaring <tt>metasearch_exclude_assoc :comments</tt> won't make any of the
|
36
|
+
# <tt>comments_*</tt> methods available.
|
37
|
+
def metasearch_exclude_assoc(*args)
|
38
|
+
args.each do |assoc|
|
39
|
+
assoc = assoc.to_s
|
40
|
+
raise(ArgumentError, "No such association #{assoc} in #{self}") unless self.reflect_on_all_associations.map {|a| a.name.to_s}.include?(assoc)
|
41
|
+
self._metasearch_exclude_associations = (self._metasearch_exclude_associations + [assoc]).uniq
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'meta_search/exceptions'
|
2
|
+
|
3
|
+
module MetaSearch
|
4
|
+
module Utility #:nodoc:
|
5
|
+
private
|
6
|
+
|
7
|
+
def array_of_arrays?(vals)
|
8
|
+
vals.is_a?(Array) && vals.first.is_a?(Array)
|
9
|
+
end
|
10
|
+
|
11
|
+
def array_of_dates?(vals)
|
12
|
+
vals.is_a?(Array) && vals.first.respond_to?(:to_time)
|
13
|
+
end
|
14
|
+
|
15
|
+
def cast_attributes(type, vals)
|
16
|
+
if array_of_arrays?(vals)
|
17
|
+
vals.map! {|v| cast_attributes(type, v)}
|
18
|
+
# Need to make sure not to kill multiparam dates/times
|
19
|
+
elsif vals.is_a?(Array) && (array_of_dates?(vals) || !(DATES+TIMES).include?(type))
|
20
|
+
vals.map! {|v| cast_attribute(type, v)}
|
21
|
+
else
|
22
|
+
cast_attribute(type, vals)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def cast_attribute(type, val)
|
27
|
+
case type
|
28
|
+
when *STRINGS
|
29
|
+
val.respond_to?(:to_s) ? val.to_s : String.new(val)
|
30
|
+
when *DATES
|
31
|
+
if val.respond_to?(:to_date)
|
32
|
+
val.to_date
|
33
|
+
else
|
34
|
+
y, m, d = *[val].flatten
|
35
|
+
m ||= 1
|
36
|
+
d ||= 1
|
37
|
+
Date.new(y,m,d) rescue nil
|
38
|
+
end
|
39
|
+
when *TIMES
|
40
|
+
if val.respond_to?(:to_time)
|
41
|
+
val.to_time
|
42
|
+
else
|
43
|
+
y, m, d, hh, mm, ss = *[val].flatten
|
44
|
+
Time.zone.local(y, m, d, hh, mm, ss) rescue nil
|
45
|
+
end
|
46
|
+
when *BOOLEANS
|
47
|
+
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(val)
|
48
|
+
when :integer
|
49
|
+
val.blank? ? nil : val.to_i
|
50
|
+
when :float
|
51
|
+
val.blank? ? nil : val.to_f
|
52
|
+
when :decimal
|
53
|
+
val.blank? ? nil : ActiveRecord::ConnectionAdapters::Column.value_to_decimal(val)
|
54
|
+
else
|
55
|
+
raise TypeCastError, "Unable to cast columns of type #{type}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def collapse_multiparameter_options(opts)
|
60
|
+
opts.each_key do |k|
|
61
|
+
if k.include?("(")
|
62
|
+
real_attribute, position = k.split(/\(|\)/)
|
63
|
+
cast = %w(a s i).include?(position.last) ? position.last : nil
|
64
|
+
position = position.to_i - 1
|
65
|
+
value = opts.delete(k)
|
66
|
+
opts[real_attribute] ||= []
|
67
|
+
opts[real_attribute][position] = if cast
|
68
|
+
(value.blank? && cast == 'i') ? nil : value.send("to_#{cast}")
|
69
|
+
else
|
70
|
+
value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
opts
|
75
|
+
end
|
76
|
+
|
77
|
+
def quote_table_name(name)
|
78
|
+
ActiveRecord::Base.connection.quote_table_name(name)
|
79
|
+
end
|
80
|
+
|
81
|
+
def quote_column_name(name)
|
82
|
+
ActiveRecord::Base.connection.quote_column_name(name)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'meta_search/exceptions'
|
2
|
+
|
3
|
+
module MetaSearch
|
4
|
+
# Wheres are how MetaSearch does its magic. Wheres have a name (and possible aliases) which are
|
5
|
+
# appended to your model and association attributes. When you instantiate a MetaSearch::Builder
|
6
|
+
# against a model (manually or by calling your model's +search+ method) the builder responds to
|
7
|
+
# methods named for your model's attributes and associations, suffixed by the name of the Where.
|
8
|
+
#
|
9
|
+
# These are the default Wheres, broken down by the types of ActiveRecord columns they can search
|
10
|
+
# against:
|
11
|
+
#
|
12
|
+
# === All data types
|
13
|
+
#
|
14
|
+
# * _equals_ (alias: _eq_) - Just as it sounds.
|
15
|
+
# * _does_not_equal_ (alias: _ne_) - The opposite of equals, oddly enough.
|
16
|
+
# * _in_ - Takes an array, matches on equality with any of the items in the array.
|
17
|
+
# * _not_in_ (alias: _ni_) - Like above, but negated.
|
18
|
+
#
|
19
|
+
# === Strings
|
20
|
+
#
|
21
|
+
# * _contains_ (alias: _like_) - Substring match.
|
22
|
+
# * _does_not_contain_ (alias: _nlike_) - Negative substring match.
|
23
|
+
# * _starts_with_ (alias: _sw_) - Match strings beginning with the entered term.
|
24
|
+
# * _does_not_start_with_ (alias: _dnsw_) - The opposite of above.
|
25
|
+
# * _ends_with_ (alias: _ew_) - Match strings ending with the entered term.
|
26
|
+
# * _does_not_end_with_ (alias: _dnew_) - Negative of above.
|
27
|
+
#
|
28
|
+
# === Numbers, dates, and times
|
29
|
+
#
|
30
|
+
# * _greater_than_ (alias: _gt_) - Greater than.
|
31
|
+
# * _greater_than_or_equal_to_ (alias: _gte_) - Greater than or equal to.
|
32
|
+
# * _less_than_ (alias: _lt_) - Less than.
|
33
|
+
# * _less_than_or_equal_to_ (alias: _lte_) - Less than or equal to.
|
34
|
+
#
|
35
|
+
# So, given a model like this...
|
36
|
+
#
|
37
|
+
# class Article < ActiveRecord::Base
|
38
|
+
# belongs_to :author
|
39
|
+
# has_many :comments
|
40
|
+
# has_many :moderations, :through => :comments
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# ...you might end up with attributes like <tt>title_contains</tt>,
|
44
|
+
# <tt>comments_title_starts_with</tt>, <tt>moderations_value_less_than</tt>,
|
45
|
+
# <tt>author_name_equals</tt>, and so on.
|
46
|
+
class Where
|
47
|
+
attr_reader :name, :aliases, :types, :condition, :substitutions, :formatter
|
48
|
+
def initialize(where)
|
49
|
+
if [String,Symbol].include?(where.class)
|
50
|
+
where = Where.get(where) or raise ArgumentError("A where could not be instantiated for the argument #{where}")
|
51
|
+
end
|
52
|
+
@name = where[:name]
|
53
|
+
@aliases = where[:aliases]
|
54
|
+
@types = where[:types]
|
55
|
+
@condition = where[:condition]
|
56
|
+
@substitutions = where[:substitutions]
|
57
|
+
@formatter = where[:formatter]
|
58
|
+
@keep_arrays = where[:keep_arrays]
|
59
|
+
end
|
60
|
+
|
61
|
+
def keep_arrays?
|
62
|
+
@keep_arrays
|
63
|
+
end
|
64
|
+
|
65
|
+
# Checks that the given +value+ is valid to use for the substitutions of this where.
|
66
|
+
# Requires that there are the same number of parameters as substitutions, and none of'
|
67
|
+
# them is blank.
|
68
|
+
def valid_substitutions?(*values)
|
69
|
+
values.flatten! unless values.size > 1 || self.keep_arrays?
|
70
|
+
self.substitutions.count('?') == values.select {|v| !v.blank?}.size
|
71
|
+
end
|
72
|
+
|
73
|
+
class << self
|
74
|
+
# At application initialization, you can add additional custom Wheres to the mix.
|
75
|
+
# in your application's <tt>config/initializers/meta_search.rb</tt>, place lines
|
76
|
+
# like this:
|
77
|
+
#
|
78
|
+
# MetaSearch::Where.add :between, :btw, {
|
79
|
+
# :types => [:integer, :float, :decimal, :date, :datetime, :timestamp, :time],
|
80
|
+
# :condition => 'BETWEEN',
|
81
|
+
# :substitutions => '? AND ?',
|
82
|
+
# :formatter => Proc.new {|param| param}
|
83
|
+
# }
|
84
|
+
#
|
85
|
+
# The first options are all names for the where. Well, the first is a name, the rest
|
86
|
+
# are aliases, really. They will determine the suffix you will use to access your Where.
|
87
|
+
#
|
88
|
+
# <tt>types</tt> is an array of types the comparison is valid for. The where will not
|
89
|
+
# be available against columns that are not one of these types. Default is +ALL_TYPES+,
|
90
|
+
# Which is one of several MetaSearch constants available for type assignment (the others
|
91
|
+
# being +DATES+, +TIIMES+, +STRINGS+, and +NUMBERS+).
|
92
|
+
#
|
93
|
+
# <tt>condition</tt> is the condition placed between the column and the substitutions, such as
|
94
|
+
# BETWEEN, IN, or =. Default is =.
|
95
|
+
#
|
96
|
+
# <tt>substitutions</tt> is the text that comes next. It's normally going to have some
|
97
|
+
# question marks in it (for variable substitution) if it's going to be of much use. The
|
98
|
+
# default is ?. Keep in mind if you use more than one ? MetaSearch will require an array
|
99
|
+
# be passed to the attribute for substitution.
|
100
|
+
#
|
101
|
+
# <tt>keep_arrays</tt> tells MetaSearch that if any arrays are received as parameters, they
|
102
|
+
# should be used as-is in the substitution, rather than flattened and passed as a list.
|
103
|
+
# For example, this is the definition of the "in" Where:
|
104
|
+
#
|
105
|
+
# ['in', {:types => ALL_TYPES, :condition => 'IN', :substitutions => '(?)',
|
106
|
+
# :keep_arrays => true}]
|
107
|
+
#
|
108
|
+
# <tt>formatter</tt> is the Proc that will do any formatting to the variables to be substituted.
|
109
|
+
# The default proc is <tt>{|param| param}</tt>, which doesn't really do anything. If you pass a
|
110
|
+
# string, it will be +eval+ed in the context of this Proc.
|
111
|
+
#
|
112
|
+
# For example, this is the definition of the "contains" Where:
|
113
|
+
#
|
114
|
+
# ['contains', 'like', {:types => STRINGS, :condition => 'LIKE', :formatter => '"%#{param}%"'}]
|
115
|
+
#
|
116
|
+
# Be sure to single-quote the string, so that variables aren't interpolated until later. If in doubt,
|
117
|
+
# just use a Proc.
|
118
|
+
def add(*args)
|
119
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
120
|
+
args = args.compact.flatten.map {|a| a.to_s }
|
121
|
+
raise ArgumentError, "Name parameter required" if args.blank?
|
122
|
+
opts[:name] ||= args.first
|
123
|
+
opts[:types] ||= ALL_TYPES
|
124
|
+
opts[:types] = [opts[:types]].flatten
|
125
|
+
opts[:condition] ||= '='
|
126
|
+
opts[:substitutions] ||= '?'
|
127
|
+
opts[:keep_arrays] ||= false
|
128
|
+
opts[:formatter] ||= Proc.new {|param| param}
|
129
|
+
if opts[:formatter].is_a?(String)
|
130
|
+
formatter = opts[:formatter]
|
131
|
+
opts[:formatter] = Proc.new {|param| eval formatter}
|
132
|
+
end
|
133
|
+
opts[:aliases] ||= [args - [opts[:name]]].flatten
|
134
|
+
@@wheres ||= {}
|
135
|
+
if @@wheres.has_key?(opts[:name])
|
136
|
+
raise ArgumentError, "\"#{opts[:name]}\" is not available for use as a where name."
|
137
|
+
end
|
138
|
+
@@wheres[opts[:name]] = opts
|
139
|
+
opts[:aliases].each do |a|
|
140
|
+
if @@wheres.has_key?(a)
|
141
|
+
opts[:aliases].delete(a)
|
142
|
+
else
|
143
|
+
@@wheres[a] = opts[:name]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns the complete array of Wheres
|
149
|
+
def all
|
150
|
+
@@wheres
|
151
|
+
end
|
152
|
+
|
153
|
+
# Get the where matching a method or condition.
|
154
|
+
def get(method_id_or_condition)
|
155
|
+
return nil unless where_key = @@wheres.keys.
|
156
|
+
sort {|a,b| b.length <=> a.length}.
|
157
|
+
detect {|n| method_id_or_condition.to_s.match(/#{n}=?$/)}
|
158
|
+
where = @@wheres[where_key]
|
159
|
+
where = @@wheres[where] if where.is_a?(String)
|
160
|
+
where
|
161
|
+
end
|
162
|
+
|
163
|
+
# Set the wheres to their default values, removing any customized settings.
|
164
|
+
def initialize_wheres
|
165
|
+
@@wheres = {}
|
166
|
+
DEFAULT_WHERES.each do |where|
|
167
|
+
add(*where)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
Where.initialize_wheres
|
174
|
+
end
|
data/lib/meta_search.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module MetaSearch
|
2
|
+
NUMBERS = [:integer, :float, :decimal]
|
3
|
+
STRINGS = [:string, :text, :binary]
|
4
|
+
DATES = [:date]
|
5
|
+
TIMES = [:datetime, :timestamp, :time]
|
6
|
+
BOOLEANS = [:boolean]
|
7
|
+
ALL_TYPES = NUMBERS + STRINGS + DATES + TIMES + BOOLEANS
|
8
|
+
|
9
|
+
DEFAULT_WHERES = [
|
10
|
+
['equals', 'eq'],
|
11
|
+
['does_not_equal', 'ne', {:types => ALL_TYPES, :condition => '!='}],
|
12
|
+
['contains', 'like', {:types => STRINGS, :condition => 'LIKE', :formatter => '"%#{param}%"'}],
|
13
|
+
['does_not_contain', 'nlike', {:types => STRINGS, :condition => 'NOT LIKE', :formatter => '"%#{param}%"'}],
|
14
|
+
['starts_with', 'sw', {:types => STRINGS, :condition => 'LIKE', :formatter => '"#{param}%"'}],
|
15
|
+
['does_not_start_with', 'dnsw', {:types => STRINGS, :condition => 'NOT LIKE', :formatter => '"%#{param}%"'}],
|
16
|
+
['ends_with', 'ew', {:types => STRINGS, :condition => 'LIKE', :formatter => '"%#{param}"'}],
|
17
|
+
['does_not_end_with', 'dnew', {:types => STRINGS, :condition => 'NOT LIKE', :formatter => '"%#{param}"'}],
|
18
|
+
['greater_than', 'gt', {:types => (NUMBERS + DATES + TIMES), :condition => '>'}],
|
19
|
+
['less_than', 'lt', {:types => (NUMBERS + DATES + TIMES), :condition => '<'}],
|
20
|
+
['greater_than_or_equal_to', 'gte', {:types => (NUMBERS + DATES + TIMES), :condition => '>='}],
|
21
|
+
['less_than_or_equal_to', 'lte', {:types => (NUMBERS + DATES + TIMES), :condition => '<='}],
|
22
|
+
['in', {:types => ALL_TYPES, :condition => 'IN', :substitutions => '(?)', :keep_arrays => true}],
|
23
|
+
['not_in', 'ni', {:types => ALL_TYPES, :condition => 'NOT IN', :substitutions => '(?)', :keep_arrays => true}]
|
24
|
+
]
|
25
|
+
|
26
|
+
RELATION_METHODS = [:joins, :includes, :all, :count, :to_sql, :paginate, :find_each, :first, :last, :each]
|
27
|
+
end
|
28
|
+
|
29
|
+
if defined?(::Rails::Railtie)
|
30
|
+
require 'meta_search/railtie'
|
31
|
+
end
|
data/meta_search.gemspec
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{meta_search}
|
8
|
+
s.version = "0.3.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ernie Miller"]
|
12
|
+
s.date = %q{2010-03-16}
|
13
|
+
s.description = %q{Adds a search method to your ActiveRecord models which returns an object to be used in form_for while constructing a search. Works with Rails 3 only.}
|
14
|
+
s.email = %q{ernie@metautonomo.us}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/meta_search.rb",
|
27
|
+
"lib/meta_search/builder.rb",
|
28
|
+
"lib/meta_search/exceptions.rb",
|
29
|
+
"lib/meta_search/helpers/action_view.rb",
|
30
|
+
"lib/meta_search/model_compatibility.rb",
|
31
|
+
"lib/meta_search/railtie.rb",
|
32
|
+
"lib/meta_search/searches/active_record.rb",
|
33
|
+
"lib/meta_search/searches/base.rb",
|
34
|
+
"lib/meta_search/utility.rb",
|
35
|
+
"lib/meta_search/where.rb",
|
36
|
+
"meta_search.gemspec",
|
37
|
+
"test/fixtures/companies.yml",
|
38
|
+
"test/fixtures/company.rb",
|
39
|
+
"test/fixtures/data_type.rb",
|
40
|
+
"test/fixtures/data_types.yml",
|
41
|
+
"test/fixtures/developer.rb",
|
42
|
+
"test/fixtures/developers.yml",
|
43
|
+
"test/fixtures/developers_projects.yml",
|
44
|
+
"test/fixtures/note.rb",
|
45
|
+
"test/fixtures/notes.yml",
|
46
|
+
"test/fixtures/project.rb",
|
47
|
+
"test/fixtures/projects.yml",
|
48
|
+
"test/fixtures/schema.rb",
|
49
|
+
"test/helper.rb",
|
50
|
+
"test/test_search.rb",
|
51
|
+
"test/test_view_helpers.rb"
|
52
|
+
]
|
53
|
+
s.homepage = %q{http://metautonomo.us}
|
54
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
55
|
+
s.require_paths = ["lib"]
|
56
|
+
s.rubygems_version = %q{1.3.6}
|
57
|
+
s.summary = %q{ActiveRecord 3 object-based searching.}
|
58
|
+
s.test_files = [
|
59
|
+
"test/fixtures/company.rb",
|
60
|
+
"test/fixtures/data_type.rb",
|
61
|
+
"test/fixtures/developer.rb",
|
62
|
+
"test/fixtures/note.rb",
|
63
|
+
"test/fixtures/project.rb",
|
64
|
+
"test/fixtures/schema.rb",
|
65
|
+
"test/helper.rb",
|
66
|
+
"test/test_search.rb",
|
67
|
+
"test/test_view_helpers.rb"
|
68
|
+
]
|
69
|
+
|
70
|
+
if s.respond_to? :specification_version then
|
71
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
72
|
+
s.specification_version = 3
|
73
|
+
|
74
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
75
|
+
s.add_development_dependency(%q<activerecord>, [">= 3.0.0.beta"])
|
76
|
+
else
|
77
|
+
s.add_dependency(%q<activerecord>, [">= 3.0.0.beta"])
|
78
|
+
end
|
79
|
+
else
|
80
|
+
s.add_dependency(%q<activerecord>, [">= 3.0.0.beta"])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
initech:
|
2
|
+
name : Initech
|
3
|
+
id : 1
|
4
|
+
created_at: 1999-02-19 08:00
|
5
|
+
updated_at: 1999-02-19 08:00
|
6
|
+
|
7
|
+
aos:
|
8
|
+
name: Advanced Optical Solutions
|
9
|
+
id : 2
|
10
|
+
created_at: 2004-02-01 08:00
|
11
|
+
updated_at: 2004-02-01 08:00
|
12
|
+
|
13
|
+
mission_data:
|
14
|
+
name: Mission Data
|
15
|
+
id : 3
|
16
|
+
created_at: 1996-09-21 08:00
|
17
|
+
updated_at: 1996-09-21 08:00
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Company < ActiveRecord::Base
|
2
|
+
has_many :developers
|
3
|
+
has_many :developer_notes, :through => :developers, :source => :notes
|
4
|
+
has_many :slackers, :class_name => "Developer", :conditions => {:slacker => true}
|
5
|
+
has_many :notes, :as => :notable
|
6
|
+
has_many :data_types
|
7
|
+
metasearch_exclude_attr :updated_at
|
8
|
+
metasearch_exclude_assoc :notes
|
9
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% 1.upto(9) do |n| %>
|
2
|
+
dt_<%= n %>:
|
3
|
+
company_id: <%= n % 3 + 1 %>
|
4
|
+
str : This string has <%= n %> exclamation points<%= '!' * n %>
|
5
|
+
txt : <%= 'This is some text that may or may not repeat based on the value of n.' * n %>
|
6
|
+
int : <%= n ** 3 %>
|
7
|
+
flt : <%= n.to_f / 2.0 %>
|
8
|
+
dec : <%= n.to_f ** (n + 0.1) %>
|
9
|
+
dtm : <%= Time.utc(2009, 12, 24) + 86400 * n %>
|
10
|
+
tms : <%= Time.utc(2009, 12, 24) + 86400 * n %>
|
11
|
+
tim : <%= Time.utc(2000, 01, 01, n+8, n) %>
|
12
|
+
dat : <%= (Date.new(2009, 12, 24) + n).strftime("%Y-%m-%d") %>
|
13
|
+
bin : <%= "BLOB#{n}" * n %>
|
14
|
+
bln : <%= n % 2 > 0 ? true : false %>
|
15
|
+
<% end %>
|
@@ -0,0 +1,55 @@
|
|
1
|
+
peter:
|
2
|
+
id : 1
|
3
|
+
company_id: 1
|
4
|
+
name : Peter Gibbons
|
5
|
+
salary : 100000
|
6
|
+
slacker : true
|
7
|
+
|
8
|
+
michael:
|
9
|
+
id : 2
|
10
|
+
company_id: 1
|
11
|
+
name : Michael Bolton
|
12
|
+
salary : 70000
|
13
|
+
slacker : false
|
14
|
+
|
15
|
+
samir:
|
16
|
+
id : 3
|
17
|
+
company_id: 1
|
18
|
+
name : Samir Nagheenanajar
|
19
|
+
salary : 65000
|
20
|
+
slacker : false
|
21
|
+
|
22
|
+
herb:
|
23
|
+
id : 4
|
24
|
+
company_id: 2
|
25
|
+
name : Herb Myers
|
26
|
+
salary : 50000
|
27
|
+
slacker : false
|
28
|
+
|
29
|
+
dude:
|
30
|
+
id : 5
|
31
|
+
company_id: 2
|
32
|
+
name : Some Dude
|
33
|
+
salary : 84000
|
34
|
+
slacker : true
|
35
|
+
|
36
|
+
ernie:
|
37
|
+
id : 6
|
38
|
+
company_id: 3
|
39
|
+
name : Ernie Miller
|
40
|
+
salary : 45000
|
41
|
+
slacker : true
|
42
|
+
|
43
|
+
someone:
|
44
|
+
id : 7
|
45
|
+
company_id: 3
|
46
|
+
name : Someone Else
|
47
|
+
salary : 70000
|
48
|
+
slacker : true
|
49
|
+
|
50
|
+
another:
|
51
|
+
id : 8
|
52
|
+
company_id: 3
|
53
|
+
name : Another Guy
|
54
|
+
salary : 80000
|
55
|
+
slacker : false
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<% 1.upto(3) do |d| %>
|
2
|
+
y2k_<%= d %>:
|
3
|
+
developer_id: <%= d %>
|
4
|
+
project_id : 1
|
5
|
+
<% end %>
|
6
|
+
|
7
|
+
virus:
|
8
|
+
developer_id: 2
|
9
|
+
project_id : 2
|
10
|
+
|
11
|
+
<% 1.upto(8) do |d| %>
|
12
|
+
awesome_<%= d %>:
|
13
|
+
developer_id: <%= d %>
|
14
|
+
project_id : 3
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
metasearch:
|
18
|
+
developer_id: 6
|
19
|
+
project_id : 4
|
20
|
+
|
21
|
+
<% 4.upto(8) do |d| %>
|
22
|
+
another_<%= d %>:
|
23
|
+
developer_id: <%= d %>
|
24
|
+
project_id : 5
|
25
|
+
<% end %>
|
@@ -0,0 +1,79 @@
|
|
1
|
+
peter:
|
2
|
+
notable_type: Developer
|
3
|
+
notable_id : 1
|
4
|
+
note : A straight shooter with upper management written all over him.
|
5
|
+
|
6
|
+
michael:
|
7
|
+
notable_type: Developer
|
8
|
+
notable_id : 2
|
9
|
+
note : Doesn't like the singer of the same name. The nerve!
|
10
|
+
|
11
|
+
samir:
|
12
|
+
notable_type: Developer
|
13
|
+
notable_id : 3
|
14
|
+
note : Naga.... Naga..... Not gonna work here anymore anyway.
|
15
|
+
|
16
|
+
herb:
|
17
|
+
notable_type: Developer
|
18
|
+
notable_id : 4
|
19
|
+
note : Will show you what he's doing.
|
20
|
+
|
21
|
+
dude:
|
22
|
+
notable_type: Developer
|
23
|
+
notable_id : 5
|
24
|
+
note : Nothing of note.
|
25
|
+
|
26
|
+
ernie:
|
27
|
+
notable_type: Developer
|
28
|
+
notable_id : 6
|
29
|
+
note : Complete slacker. Should probably be fired.
|
30
|
+
|
31
|
+
someone:
|
32
|
+
notable_type: Developer
|
33
|
+
notable_id : 7
|
34
|
+
note : Just another developer.
|
35
|
+
|
36
|
+
another:
|
37
|
+
notable_type: Developer
|
38
|
+
notable_id : 8
|
39
|
+
note : Placing a note in this guy's file for insubordination.
|
40
|
+
|
41
|
+
initech:
|
42
|
+
notable_type: Company
|
43
|
+
notable_id : 1
|
44
|
+
note : Innovation + Technology!
|
45
|
+
|
46
|
+
aos:
|
47
|
+
notable_type: Company
|
48
|
+
notable_id : 2
|
49
|
+
note : Advanced solutions of an optical nature.
|
50
|
+
|
51
|
+
mission_data:
|
52
|
+
notable_type: Company
|
53
|
+
notable_id : 3
|
54
|
+
note : Best design + development shop in the 'ville.
|
55
|
+
|
56
|
+
y2k:
|
57
|
+
notable_type: Project
|
58
|
+
notable_id : 1
|
59
|
+
note : It may have already passed but that's no excuse to be unprepared!
|
60
|
+
|
61
|
+
virus:
|
62
|
+
notable_type: Project
|
63
|
+
notable_id : 2
|
64
|
+
note : It could bring the company to its knees.
|
65
|
+
|
66
|
+
awesome:
|
67
|
+
notable_type: Project
|
68
|
+
notable_id : 3
|
69
|
+
note : This note is AWESOME!!!
|
70
|
+
|
71
|
+
metasearch:
|
72
|
+
notable_type: Project
|
73
|
+
notable_id : 4
|
74
|
+
note : A complete waste of the developer's time.
|
75
|
+
|
76
|
+
another:
|
77
|
+
notable_type: Project
|
78
|
+
notable_id : 5
|
79
|
+
note : This is another project note.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
y2k:
|
2
|
+
estimated_hours: 1000
|
3
|
+
name : Y2K Software Updates
|
4
|
+
id : 1
|
5
|
+
|
6
|
+
virus:
|
7
|
+
estimated_hours: 80
|
8
|
+
name : Virus
|
9
|
+
id : 2
|
10
|
+
|
11
|
+
awesome:
|
12
|
+
estimated_hours: 100
|
13
|
+
name : Do something awesome
|
14
|
+
id : 3
|
15
|
+
|
16
|
+
metasearch:
|
17
|
+
estimated_hours: 100
|
18
|
+
name : MetaSearch Development
|
19
|
+
id : 4
|
20
|
+
|
21
|
+
another:
|
22
|
+
estimated_hours: 120
|
23
|
+
name : Another Project
|
24
|
+
id : 5
|