meta_where 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ module MetaWhere
2
+ class Compound
3
+ attr_reader :condition1, :condition2
4
+
5
+ def initialize(condition1, condition2)
6
+ @condition1 = condition1
7
+ @condition2 = condition2
8
+ end
9
+
10
+ def |(other)
11
+ Or.new(self, other)
12
+ end
13
+
14
+ def &(other)
15
+ And.new(self, other)
16
+ end
17
+ end
18
+
19
+ class Or < Compound
20
+ def to_predicate(builder, parent = nil)
21
+ condition1.to_predicate(builder, parent).or(condition2.to_predicate(builder, parent))
22
+ end
23
+ end
24
+
25
+ class And < Compound
26
+ def to_predicate(builder, parent = nil)
27
+ condition1.to_predicate(builder, parent).and(condition2.to_predicate(builder, parent))
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,51 @@
1
+ require 'meta_where/utility'
2
+
3
+ module MetaWhere
4
+ class Condition
5
+ include MetaWhere::Utility
6
+
7
+ attr_reader :column, :value, :method
8
+
9
+ def initialize(column, value, method)
10
+ @column = column.to_s
11
+ @value = value
12
+ @method = (MetaWhere::METHOD_ALIASES[method.to_s] || method).to_s
13
+ end
14
+
15
+ def to_predicate(builder, parent = nil)
16
+ table = builder.build_table(parent)
17
+
18
+ unless attribute = table[column]
19
+ raise ::ActiveRecord::StatementInvalid, "No attribute named `#{column}` exists for table `#{table.name}`"
20
+ end
21
+
22
+ unless valid_comparison_method?(method)
23
+ raise ::ActiveRecord::StatementInvalid, "No comparison method named `#{method}` exists for column `#{column}`"
24
+ end
25
+ attribute.send(method, *args_for_predicate(method.to_s, value))
26
+ end
27
+
28
+ def ==(other_condition)
29
+ other_condition.is_a?(Condition) &&
30
+ other_condition.column == column &&
31
+ other_condition.value = value &&
32
+ other_condition.method == method
33
+ end
34
+
35
+ alias_method :eql?, :==
36
+
37
+ def |(other)
38
+ Or.new(self, other)
39
+ end
40
+
41
+ def &(other)
42
+ And.new(self, other)
43
+ end
44
+
45
+ # Play "nicely" with expand_hash_conditions_for_aggregates
46
+ def to_sym
47
+ self
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,48 @@
1
+ module MetaWhere
2
+ module JoinDependency
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ alias_method_chain :build, :metawhere
7
+ end
8
+ end
9
+
10
+ class BaseMismatchError < StandardError; end
11
+ class ConfigurationError < StandardError; end
12
+ class AssociationNotFoundError < StandardError; end
13
+
14
+ def build_with_metawhere(associations, parent = nil, join_class = Arel::InnerJoin)
15
+ parent ||= @joins.last
16
+ case associations
17
+ when Symbol, String
18
+ reflection = parent.reflections[associations.to_s.intern] or
19
+ raise AssociationNotFoundError, "Association named '#{ associations }' was not found; perhaps you misspelled it?"
20
+ unless association = find_join_association(reflection, parent)
21
+ @reflections << reflection
22
+ association = (@joins << build_join_association(reflection, parent).with_join_class(join_class)).last
23
+ end
24
+ association
25
+ when Array
26
+ associations.each do |association|
27
+ build(association, parent, join_class)
28
+ end
29
+ when Hash
30
+ associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
31
+ association = build(name, parent, join_class)
32
+ build(associations[name], association, join_class)
33
+ end
34
+ else
35
+ raise ConfigurationError, associations.inspect
36
+ end
37
+ end
38
+
39
+ def find_join_association(name_or_reflection, parent)
40
+ case name_or_reflection
41
+ when Symbol, String
42
+ join_associations.detect {|j| (j.reflection.name == name_or_reflection.to_s.intern) && (j.parent == parent)}
43
+ else
44
+ join_associations.detect {|j| (j.reflection == name_or_reflection) && (j.parent == parent)}
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,270 @@
1
+ module MetaWhere
2
+ module Relation
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ alias_method_chain :reset, :metawhere
7
+ alias_method_chain :scope_for_create, :metawhere
8
+ end
9
+ end
10
+
11
+ def merge(r, association_name = nil)
12
+ if (r && (association_name || klass.name != r.klass.name)) # Merging relations with different base.
13
+ association_name ||= (default_association = reflect_on_all_associations.detect {|a| a.klass.name == r.klass.name}) ?
14
+ default_association.name : r.table_name.to_sym
15
+ r = r.clone
16
+ r.where_values.map! {|w| w.respond_to?(:to_predicate) ? {association_name => w} : w}
17
+ r.joins_values.map! {|j| [Symbol, Hash].include?(j.class) ? {association_name => j} : j}
18
+ self.joins_values += [association_name]
19
+ end
20
+ super(r)
21
+ end
22
+
23
+ alias_method :&, :merge
24
+
25
+ def reset_with_metawhere
26
+ @mw_unique_joins = @mw_association_joins = @mw_non_association_joins =
27
+ @mw_stashed_association_joins = @mw_custom_joins = nil
28
+ reset_without_metawhere
29
+ end
30
+
31
+ def scope_for_create_with_metawhere
32
+ @scope_for_create ||= begin
33
+ @create_with_value || predicate_wheres.inject({}) do |hash, where|
34
+ if is_equality_predicate?(where)
35
+ hash[where.operand1.name] = where.operand2.respond_to?(:value) ? where.operand2.value : where.operand2
36
+ end
37
+
38
+ hash
39
+ end
40
+ end
41
+ end
42
+
43
+ def build_where(opts, other = [])
44
+ if opts.is_a?(String)
45
+ @klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))
46
+ else
47
+ predicates = []
48
+ [opts, *other].each do |arg|
49
+ predicates += Array.wrap(
50
+ case arg
51
+ when Array
52
+ @klass.send(:sanitize_sql, arg)
53
+ when Hash
54
+ @klass.send(:expand_hash_conditions_for_aggregates, arg)
55
+ else
56
+ arg
57
+ end
58
+ )
59
+ end
60
+ predicates
61
+ end
62
+ end
63
+
64
+ def build_custom_joins(joins = [], arel = nil)
65
+ arel ||= table
66
+ joins.each do |join|
67
+ next if join.blank?
68
+
69
+ @implicit_readonly = true
70
+
71
+ case join
72
+ when ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation
73
+ arel = arel.join(join.relation, Arel::OuterJoin).on(*join.on)
74
+ when Hash, Array, Symbol
75
+ if array_of_strings?(join)
76
+ join_string = join.join(' ')
77
+ arel = arel.join(join_string)
78
+ end
79
+ else
80
+ arel = arel.join(join)
81
+ end
82
+ end
83
+
84
+ arel
85
+ end
86
+
87
+ def custom_join_sql(*joins)
88
+ arel = table
89
+ joins.each do |join|
90
+ next if join.blank?
91
+
92
+ @implicit_readonly = true
93
+
94
+ case join
95
+ when Hash, Array, Symbol
96
+ if array_of_strings?(join)
97
+ join_string = join.join(' ')
98
+ arel = arel.join(join_string)
99
+ end
100
+ else
101
+ arel = arel.join(join)
102
+ end
103
+ end
104
+ arel.joins(arel)
105
+ end unless defined?(:custom_join_sql)
106
+
107
+ def predicate_wheres
108
+ remove_conflicting_equality_predicates(flatten_predicates(@where_values, metawhere_builder))
109
+ end
110
+
111
+ # Very occasionally, we need to get a builder for another relation, so it makes sense to factor
112
+ # this out into a public method despite only being two lines long.
113
+ def metawhere_builder
114
+ join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, custom_joins)
115
+ MetaWhere::Builder.new(join_dependency)
116
+ end
117
+
118
+ # Simulate the logic that occurs in ActiveRecord::Relation.to_a
119
+ #
120
+ # @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql)
121
+ #
122
+ # This will let us get a dump of the SQL that will be run against the DB for debug
123
+ # purposes without actually running the query.
124
+ def debug_sql
125
+ if eager_loading?
126
+ including = (@eager_load_values + @includes_values).uniq
127
+ join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, nil)
128
+ construct_relation_for_association_find(join_dependency).to_sql
129
+ else
130
+ arel.to_sql
131
+ end
132
+ end
133
+
134
+ def construct_limited_ids_condition(relation)
135
+ builder = relation.metawhere_builder
136
+
137
+ relation.order_values.map! {|o| o.respond_to?(:to_attribute) ? o.to_attribute(builder).to_sql : o}
138
+
139
+ super
140
+ end
141
+
142
+ def build_arel
143
+ arel = table
144
+
145
+ builder = metawhere_builder
146
+
147
+ arel = build_intelligent_joins(arel, builder) if @joins_values.present?
148
+
149
+ predicate_wheres = remove_conflicting_equality_predicates(flatten_predicates(@where_values, builder))
150
+
151
+ predicate_wheres.each do |where|
152
+ next if where.blank?
153
+
154
+ case where
155
+ when Arel::SqlLiteral
156
+ arel = arel.where(where)
157
+ else
158
+ sql = where.is_a?(String) ? where : where.to_sql
159
+ arel = arel.where(Arel::SqlLiteral.new("(#{sql})"))
160
+ end
161
+ end
162
+
163
+ arel = arel.having(*@having_values.uniq.select{|h| h.present?}) if @having_values.present?
164
+
165
+ arel = arel.take(@limit_value) if @limit_value.present?
166
+ arel = arel.skip(@offset_value) if @offset_value.present?
167
+
168
+ arel = arel.group(*@group_values.uniq.select{|g| g.present?}) if @group_values.present?
169
+
170
+ arel = build_order(arel, builder, @order_values) if @order_values.present?
171
+
172
+ arel = build_select(arel, @select_values.uniq)
173
+
174
+ arel = arel.from(@from_value) if @from_value.present?
175
+
176
+ case @lock_value
177
+ when TrueClass
178
+ arel = arel.lock
179
+ when String
180
+ arel = arel.lock(@lock_value)
181
+ end if @lock_value.present?
182
+
183
+ arel
184
+ end
185
+
186
+ private
187
+
188
+ def is_equality_predicate?(predicate)
189
+ predicate.respond_to?(:operator) && predicate.operator == :==
190
+ end
191
+
192
+ def build_intelligent_joins(arel, builder)
193
+ joined_associations = []
194
+
195
+ builder.join_dependency.graft(*stashed_association_joins)
196
+
197
+ @implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
198
+
199
+ to_join = []
200
+
201
+ builder.join_dependency.join_associations.each do |association|
202
+ if (association_relation = association.relation).is_a?(Array)
203
+ to_join << [association_relation.first, association.join_class, association.association_join.first]
204
+ to_join << [association_relation.last, association.join_class, association.association_join.last]
205
+ else
206
+ to_join << [association_relation, association.join_class, association.association_join]
207
+ end
208
+ end
209
+
210
+ to_join.each do |tj|
211
+ unless joined_associations.detect {|ja| ja[0] == tj[0] && ja[1] == tj[1] && ja[2] == tj[2] }
212
+ joined_associations << tj
213
+ arel = arel.join(tj[0], tj[1]).on(*tj[2])
214
+ end
215
+ end
216
+
217
+ arel = arel.join(custom_joins)
218
+ end
219
+
220
+ def build_order(arel, builder, orders)
221
+ order_attributes = orders.map {|o|
222
+ o.respond_to?(:to_attribute) ? o.to_attribute(builder, builder.join_dependency.join_base) : o
223
+ }.flatten.uniq.select {|o| o.present?}
224
+ order_attributes.map! {|a| Arel::SqlLiteral.new(a.is_a?(String) ? a : a.to_sql)}
225
+ order_attributes.present? ? arel.order(*order_attributes) : arel
226
+ end
227
+
228
+ def remove_conflicting_equality_predicates(predicates)
229
+ predicates.reverse.inject([]) { |ary, w|
230
+ unless is_equality_predicate?(w) && ary.any? {|p| is_equality_predicate?(p) && p.operand1.name == w.operand1.name}
231
+ ary << w
232
+ end
233
+ ary
234
+ }.reverse
235
+ end
236
+
237
+ def flatten_predicates(predicates, builder)
238
+ predicates.map {|p|
239
+ predicate = p.respond_to?(:to_predicate) ? p.to_predicate(builder) : p
240
+ if predicate.is_a?(Arel::Predicates::All)
241
+ flatten_predicates(predicate.predicates, builder)
242
+ else
243
+ predicate
244
+ end
245
+ }.flatten.uniq
246
+ end
247
+
248
+ def unique_joins
249
+ @mw_unique_joins ||= @joins_values.map {|j| j.respond_to?(:strip) ? j.strip : j}.uniq
250
+ end
251
+
252
+ def association_joins
253
+ @mw_association_joins ||= unique_joins.select{|j|
254
+ [Hash, Array, Symbol].include?(j.class) && !array_of_strings?(j)
255
+ }
256
+ end
257
+
258
+ def stashed_association_joins
259
+ @mw_stashed_association_joins ||= unique_joins.select {|j| j.is_a?(ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation)}
260
+ end
261
+
262
+ def non_association_joins
263
+ @mw_non_association_joins ||= (unique_joins - association_joins - stashed_association_joins).reject {|j| j.blank?}
264
+ end
265
+
266
+ def custom_joins
267
+ @mw_custom_joins ||= custom_join_sql(*non_association_joins)
268
+ end
269
+ end
270
+ end
@@ -0,0 +1,27 @@
1
+ module MetaWhere
2
+ module Utility
3
+ private
4
+
5
+ def args_for_predicate(method, value)
6
+ value = [Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Relation].include?(value.class) ? value.to_a : value
7
+ if method =~ /_(any|all)$/ && value.is_a?(Array)
8
+ value
9
+ else
10
+ [value]
11
+ end
12
+ end
13
+
14
+ def method_from_value(value)
15
+ case value
16
+ when Array, Range, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Relation
17
+ :in
18
+ else
19
+ :eq
20
+ end
21
+ end
22
+
23
+ def valid_comparison_method?(method)
24
+ Arel::Attribute::PREDICATES.map(&:to_s).include?(method.to_s)
25
+ end
26
+ end
27
+ end
data/lib/meta_where.rb ADDED
@@ -0,0 +1,27 @@
1
+ module MetaWhere
2
+ METHOD_ALIASES = {
3
+ 'ne' => :not_eq,
4
+ 'like' => :matches,
5
+ 'nlike' => :not_matches,
6
+ 'lte' => :lteq,
7
+ 'gte' => :gteq,
8
+ 'nin' => :not_in
9
+ }
10
+
11
+ def self.operator_overload!
12
+ require 'core_ext/symbol_operators'
13
+ end
14
+ end
15
+ require 'arel'
16
+ require 'active_record'
17
+ require 'active_support'
18
+ require 'meta_where/column'
19
+ require 'meta_where/condition'
20
+ require 'meta_where/compound'
21
+ require 'core_ext/symbol'
22
+ require 'core_ext/hash'
23
+ require 'meta_where/builder'
24
+ require 'meta_where/relation'
25
+ require 'meta_where/join_dependency'
26
+ ActiveRecord::Relation.send(:include, MetaWhere::Relation)
27
+ ActiveRecord::Associations::ClassMethods::JoinDependency.send(:include, MetaWhere::JoinDependency)
@@ -0,0 +1,105 @@
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_where}
8
+ s.version = "0.9.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-08-24}
13
+ s.description = %q{
14
+ MetaWhere offers the ability to call any Arel predicate methods
15
+ (with a few convenient aliases) on your Model's attributes instead
16
+ of the ones normally offered by ActiveRecord's hash parameters. It also
17
+ adds convenient syntax for order clauses, smarter mapping of nested hash
18
+ conditions, and a debug_sql method to see the real SQL your code is
19
+ generating without running it against the database. If you like the new
20
+ AR 3.0 query interface, you'll love it with MetaWhere.
21
+ }
22
+ s.email = %q{ernie@metautonomo.us}
23
+ s.extra_rdoc_files = [
24
+ "LICENSE",
25
+ "README.rdoc"
26
+ ]
27
+ s.files = [
28
+ ".document",
29
+ ".gitignore",
30
+ ".gitmodules",
31
+ "CHANGELOG",
32
+ "Gemfile",
33
+ "LICENSE",
34
+ "README.rdoc",
35
+ "Rakefile",
36
+ "VERSION",
37
+ "lib/core_ext/hash.rb",
38
+ "lib/core_ext/symbol.rb",
39
+ "lib/core_ext/symbol_operators.rb",
40
+ "lib/meta_where.rb",
41
+ "lib/meta_where/builder.rb",
42
+ "lib/meta_where/column.rb",
43
+ "lib/meta_where/compound.rb",
44
+ "lib/meta_where/condition.rb",
45
+ "lib/meta_where/join_dependency.rb",
46
+ "lib/meta_where/relation.rb",
47
+ "lib/meta_where/utility.rb",
48
+ "meta_where.gemspec",
49
+ "test/fixtures/companies.yml",
50
+ "test/fixtures/company.rb",
51
+ "test/fixtures/data_type.rb",
52
+ "test/fixtures/data_types.yml",
53
+ "test/fixtures/developer.rb",
54
+ "test/fixtures/developers.yml",
55
+ "test/fixtures/developers_projects.yml",
56
+ "test/fixtures/note.rb",
57
+ "test/fixtures/notes.yml",
58
+ "test/fixtures/people.yml",
59
+ "test/fixtures/person.rb",
60
+ "test/fixtures/project.rb",
61
+ "test/fixtures/projects.yml",
62
+ "test/fixtures/schema.rb",
63
+ "test/helper.rb",
64
+ "test/test_relations.rb"
65
+ ]
66
+ s.homepage = %q{http://metautonomo.us/projects/metawhere/}
67
+ s.rdoc_options = ["--charset=UTF-8"]
68
+ s.require_paths = ["lib"]
69
+ s.rubygems_version = %q{1.3.7}
70
+ s.summary = %q{Add a dash of Arel awesomeness to your condition hashes.}
71
+ s.test_files = [
72
+ "test/fixtures/company.rb",
73
+ "test/fixtures/data_type.rb",
74
+ "test/fixtures/developer.rb",
75
+ "test/fixtures/note.rb",
76
+ "test/fixtures/person.rb",
77
+ "test/fixtures/project.rb",
78
+ "test/fixtures/schema.rb",
79
+ "test/helper.rb",
80
+ "test/test_relations.rb"
81
+ ]
82
+
83
+ if s.respond_to? :specification_version then
84
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
85
+ s.specification_version = 3
86
+
87
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
88
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
89
+ s.add_runtime_dependency(%q<activerecord>, ["~> 3.0.0.rc2"])
90
+ s.add_runtime_dependency(%q<activesupport>, ["~> 3.0.0.rc2"])
91
+ s.add_runtime_dependency(%q<arel>, ["~> 1.0.0.rc1"])
92
+ else
93
+ s.add_dependency(%q<shoulda>, [">= 0"])
94
+ s.add_dependency(%q<activerecord>, ["~> 3.0.0.rc2"])
95
+ s.add_dependency(%q<activesupport>, ["~> 3.0.0.rc2"])
96
+ s.add_dependency(%q<arel>, ["~> 1.0.0.rc1"])
97
+ end
98
+ else
99
+ s.add_dependency(%q<shoulda>, [">= 0"])
100
+ s.add_dependency(%q<activerecord>, ["~> 3.0.0.rc2"])
101
+ s.add_dependency(%q<activesupport>, ["~> 3.0.0.rc2"])
102
+ s.add_dependency(%q<arel>, ["~> 1.0.0.rc1"])
103
+ end
104
+ end
105
+
@@ -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,7 @@
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
+ end
@@ -0,0 +1,3 @@
1
+ class DataType < ActiveRecord::Base
2
+ belongs_to :company
3
+ 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).to_s(:db) %>
10
+ tms : <%= (Time.utc(2009, 12, 24) + 86400 * n).to_s(:db) %>
11
+ tim : <%= Time.utc(2000, 01, 01, n+8, n).to_s(:db) %>
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,5 @@
1
+ class Developer < ActiveRecord::Base
2
+ belongs_to :company
3
+ has_and_belongs_to_many :projects
4
+ has_many :notes, :as => :notable
5
+ 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 %>