mack-data_factory 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,167 @@
1
+ Mack-data_factory
2
+ -----------------------------------------------------------------------------
3
+
4
+ == Summary
5
+ Utility to create faux data.
6
+
7
+ == Installation
8
+ sudo gem install mack-data_factory
9
+
10
+ == Using The Gem
11
+
12
+ ** Constructing Factory
13
+ For each model that you want to produce, you will need to define a factory class.
14
+ Let's say that I have 2 models: Item and User, and Item belongs to user. So the factories will look like the following:
15
+
16
+ class ItemFactory
17
+ include Mack::Data::Factory
18
+
19
+ field :title, "MyItem"
20
+ field :owner_id, {:user => 'id'}
21
+ end
22
+
23
+ class UserFactory
24
+ include Mack::Data::Factory
25
+
26
+ field :username, "planters", :length => 25, :content => :alpha
27
+ field :password, "roastedPeanuts", :immutable => true
28
+ end
29
+
30
+ So, the 2 classes above defined the factory for item and user. As you can see, each factory will need to explicitly
31
+ list all the fields that it will populate, and for each field, you can define rules on how the content is generated.
32
+ Important: For each field defined in the factory, you will need to make sure that there's a corresponding setter
33
+ method in the model class (e.g. Item class is required to have title= and owner_id=).
34
+
35
+ For numeric content, you can specify the start number and end number, and the content generator will generate a random number
36
+ between that range.
37
+
38
+ For all fields, you can specify :immutable to true, which means for all instances created, the content for that field
39
+ will not change.
40
+
41
+
42
+ Supported content types:
43
+ # Strings and Numbers
44
+ - :alpha --> alphabets. rules: [:length, :min_length, :max_length]
45
+ - :alphanumeric --> alphabets and number. rules: same as :alpha
46
+ - :numeric --> numbers [optional, because if the field's default value is number, its content type will automatically set to numeric)
47
+ # Internet related content
48
+ - :email --> generate random email address
49
+ - :username --> generate random username
50
+ - :domain --> generate random domain name
51
+ # Name related info
52
+ - :firstname --> generate first name
53
+ - :lastname --> generate last name
54
+ - :name --> generate full name
55
+ # Address related info
56
+ - :city --> generate city name
57
+ - :streetname --> generate street name
58
+ - :state --> generate state. rules: [:country --> :us or :uk, :abbr --> true if you want a abbreviated state name (us only)]
59
+ - :zipcode --> generate zipcode. rules: [:country --> :us or :uk]
60
+ - :phone --> generate phone number
61
+ # Company info
62
+ - :company --> generate company name. rules: [:include_bs --> include sales tag line]
63
+ example: field, "", :content => :company, :include_bs => true
64
+ could generate something like:
65
+ Fadel-Larkin
66
+ monetize cross-media experiences
67
+
68
+ ** Association
69
+ class ItemFactory
70
+ include Mack::Data::Factory
71
+
72
+ field :title, "MyItem"
73
+ field :owner_id, {:user => 'id'}, {:assoc => :first}
74
+ end
75
+
76
+ class UserFactory
77
+ include Mack::Data::Factory
78
+
79
+ field :username, "planters", :length => 25, :content => :alpha
80
+ field :password, "roastedPeanuts", :immutable => true
81
+ end
82
+
83
+ In the above example, the ItemFactory define the owner_id field's value as {:user => 'id'}. When the factory is run,
84
+ it will generate value for owner_id as 'the id of the user #x'. You can also pass in rules to define which instance
85
+ of user that the id will be retrieved from. The rules are: :first, :last, :random, and :spread. The default is :spread.
86
+ Definition of the association rules:
87
+ :first --> always associate with the first object that this object belongs to. If there are 10 users [id = 0 - 10], then the item will always get associated with user #0 (i.e. item's owner_id always == 0)
88
+ :last --> always associate with the last object that this object belongs to. If there are 10 users [id = 0 - 10], then the item will always get associated with user #10 (i.e. item's owner_id always == 9)
89
+ :random --> always associate with the Nth object that this object belongs to (and N is random). If there are 10 users [id = 0 - 10], then the item will get associated with user #n (i.e. item's owner_id == rand(10))
90
+ :spread --> spread the association. If there are 3 users [id = 0 - 2], then the items' association will be spread out (i.e. 6 items will have id--sequentially--[0, 1, 2, 0, 1, 2])
91
+
92
+ ** Pumping Data
93
+
94
+ To create objects from the factory is very easy, just call create method on that factory and tell it how many items
95
+ you want to create.
96
+
97
+ Note that if your factory has dependencies to other model (like the ItemFactory in the example), then make sure you
98
+ have created the model that it's depending on first.
99
+
100
+ The create method will return constructed objects. If there's only 1 instance constructed, then it will return that object;
101
+ if more than one then it will return an array of objects.
102
+
103
+ ** Creating Factories Execution Chain
104
+ In some instances, you may want to create an execution chain of a bunch of factories. In the above example: the UserFactory
105
+ has to be run before the ItemFactory.
106
+ If that's the case, you can create factory chain that you can execute later.
107
+
108
+ factories(:my_cool_factory) do
109
+ UserFactory.create(1)
110
+ ItemFactory.create(1000)
111
+ end
112
+
113
+ Once you have defined a named factory chain, you can execute that any time, by calling:
114
+
115
+ run_factories(:my_cool_factory)
116
+
117
+ ** Scoping
118
+ In other instances, you may want different settings in the factory for different test scope. You can achieve this by doing
119
+ the following:
120
+
121
+ class UserFactory
122
+ include Mack::Data::Factory
123
+
124
+ field :username, "planters", :length => 25, :content => :alpha
125
+ field :password, "roastedPeanuts", :immutable => true
126
+
127
+ scope_for(:long_username) do
128
+ field :username, "planters", :length => 128, :content => :alpha
129
+ end
130
+ end
131
+
132
+ The above example defined a scoping for "long_username", which you can use by calling:
133
+ UserFactory.create(100, :long_username)
134
+
135
+ When a scope is defined and called, the field defined in the block will overwrite the default field listing
136
+ in that class. Scopes in the factory is independent to each other, and one scope cannot affect the others.
137
+
138
+ ** Custom content generator
139
+ In some cases, the default content generators that are provided by this framework don't fit your needs.
140
+ To accommodate this situation, you can provide a custom content generator for each field you defined by
141
+ passing in a proc.
142
+
143
+ Example:
144
+ I'm creating a users, but I don't want the username be totally random, instead I want it to use the default
145
+ name I provide, and append 0-n at the end of the string to represent the Nth user in the list. Here's how to
146
+ accomplish that:
147
+ class UserFactory
148
+ include Mack::Data::Factory
149
+
150
+ field :username, "planters" do |def_value, rules, index|
151
+ "#{def_value}#{index}"
152
+ end
153
+ field :password, "roastedPeanuts", :immutable => true
154
+
155
+ end
156
+
157
+ == Contact
158
+ Please mail bugs, suggestions, and patches to darsono.sutedja@gmail.com
159
+
160
+ == Copyright Notices
161
+ Copyright (c) 2008 Darsono Sutedja
162
+
163
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
164
+
165
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
166
+
167
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,217 @@
1
+ module Mack
2
+ module Data
3
+ module Factory
4
+
5
+ class FieldContentGenerator
6
+ class << self
7
+ def alpha_generator
8
+ @alpha_gen = Proc.new do |def_value, rules, index|
9
+ words = %w(alias consequatur aut perferendis sit voluptatem accusantium doloremque aperiam eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo aspernatur aut odit aut fugit sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt neque dolorem ipsum quia dolor sit amet consectetur adipisci velit sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem ut enim ad minima veniam quis nostrum exercitationem ullam corporis nemo enim ipsam voluptatem quia voluptas sit suscipit laboriosam nisi ut aliquid ex ea commodi consequatur quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae et iusto odio dignissimos ducimus qui blanditiis praesentium laudantium totam rem voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident sed ut perspiciatis unde omnis iste natus error similique sunt in culpa qui officia deserunt mollitia animi id est laborum et dolorum fuga et harum quidem rerum facilis est et expedita distinctio nam libero tempore cum soluta nobis est eligendi optio cumque nihil impedit quo porro quisquam est qui minus id quod maxime placeat facere possimus omnis voluptas assumenda est omnis dolor repellendus temporibus autem quibusdam et aut consequatur vel illum qui dolorem eum fugiat quo voluptas nulla pariatur at vero eos et accusamus officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae itaque earum rerum hic tenetur a sapiente delectus ut aut reiciendis voluptatibus maiores doloribus asperiores repellat)
10
+
11
+ length = 128
12
+ min_length = -1
13
+ max_length = -1
14
+
15
+ if rules[:min_length]
16
+ min_length = rules[:min_length].to_i
17
+ end
18
+
19
+ if rules[:max_length]
20
+ max_length = rules[:max_length].to_i
21
+ end
22
+
23
+ if rules[:length]
24
+ length = rules[:length].to_i
25
+ length = max_length if (max_length != -1) and (max_length <= length)
26
+ end
27
+
28
+ ret_val = ""
29
+ words_size = words.size
30
+ until ret_val.size > length do
31
+ i = (rand * 100).to_i
32
+ i = words_size if (i-1) > words_size
33
+
34
+ ret_val += words[i]
35
+ ret_val += " " if rules[:add_space]
36
+ end
37
+
38
+ ret_val.strip!
39
+
40
+ ret_val = ret_val[0, length] if ret_val.size > length
41
+
42
+ ret_val
43
+ end
44
+ return @alpha_gen
45
+ end
46
+
47
+ def alpha_numeric_generator
48
+ @alpha_numeric_gen = Proc.new do |def_value, rules, index|
49
+ words = %w(alias consequatur aut perferendis sit voluptatem accusantium doloremque aperiam eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo aspernatur aut odit aut fugit sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt neque dolorem ipsum quia dolor sit amet consectetur adipisci velit sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem ut enim ad minima veniam quis nostrum exercitationem ullam corporis nemo enim ipsam voluptatem quia voluptas sit suscipit laboriosam nisi ut aliquid ex ea commodi consequatur quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae et iusto odio dignissimos ducimus qui blanditiis praesentium laudantium totam rem voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident sed ut perspiciatis unde omnis iste natus error similique sunt in culpa qui officia deserunt mollitia animi id est laborum et dolorum fuga et harum quidem rerum facilis est et expedita distinctio nam libero tempore cum soluta nobis est eligendi optio cumque nihil impedit quo porro quisquam est qui minus id quod maxime placeat facere possimus omnis voluptas assumenda est omnis dolor repellendus temporibus autem quibusdam et aut consequatur vel illum qui dolorem eum fugiat quo voluptas nulla pariatur at vero eos et accusamus officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae itaque earum rerum hic tenetur a sapiente delectus ut aut reiciendis voluptatibus maiores doloribus asperiores repellat)
50
+
51
+ length = 128
52
+ min_length = -1
53
+ max_length = -1
54
+
55
+ if rules[:min_length]
56
+ min_length = rules[:min_length].to_i
57
+ end
58
+
59
+ if rules[:max_length]
60
+ max_length = rules[:max_length].to_i
61
+ end
62
+
63
+ if rules[:length]
64
+ length = rules[:length].to_i
65
+ length = max_length if (max_length != -1) and (max_length <= length)
66
+ end
67
+
68
+ ret_val = ""
69
+ words_size = words.size
70
+ until ret_val.size > length do
71
+ i = (rand * 100).to_i
72
+ i = words_size if (i-1) > words_size
73
+
74
+ ret_val += (words[i] + (rand * 1000).to_i.to_s)
75
+ ret_val += " " if rules[:add_space]
76
+ end
77
+
78
+ ret_val.strip!
79
+
80
+ ret_val = ret_val[0, length] if ret_val.size > length
81
+
82
+ ret_val
83
+ end
84
+ return @alpha_numeric_gen
85
+ end
86
+
87
+ def numeric_generator
88
+ @numeric_gen = Proc.new do |def_value, rules, index|
89
+ n_start = rules[:start_num] || 0
90
+ n_end = rules[:end_num] || 1000
91
+
92
+ val = (n_start..n_end).to_a.randomize[0]
93
+ val
94
+ end
95
+ return @numeric_gen
96
+ end
97
+
98
+ def date_generator
99
+ @date_gen = Proc.new do |def_value, rules, index|
100
+ Time.now.to_s
101
+ end
102
+ return @date_gen
103
+ end
104
+
105
+ def date_time_generator
106
+ @date_time_gen = Proc.new do |def_value, rules, index|
107
+ Time.now.to_s
108
+ end
109
+ return @date_time_gen
110
+ end
111
+
112
+
113
+ def email_generator
114
+ @email_gen = Proc.new do |def_value, rules, index|
115
+ Faker::Internet.free_email
116
+ end
117
+ return @email_gen
118
+ end
119
+
120
+ def username_generator
121
+ @username_gen = Proc.new do |def_value, rules, index|
122
+ Faker::Internet.user_name
123
+ end
124
+ return @username_gen
125
+ end
126
+
127
+ def domain_generator
128
+ @domain_gen = Proc.new do |def_value, rules, index|
129
+ Faker::Internet.domain_name
130
+ end
131
+ return @domain_gen
132
+ end
133
+
134
+ def firstname_generator
135
+ @fn_gen = Proc.new do |def_value, rules, index|
136
+ Faker::Name.first_name
137
+ end
138
+ return @fn_gen
139
+ end
140
+
141
+ def lastname_generator
142
+ @ln_gen = Proc.new do |def_value, rules, index|
143
+ Faker::Name.last_name
144
+ end
145
+ return @ln_gen
146
+ end
147
+
148
+ def phone_generator
149
+ @phone_gen = Proc.new do |def_value, rules, index|
150
+ Faker::PhoneNumber.phone_number
151
+ end
152
+ return @phone_gen
153
+ end
154
+
155
+ def company_generator
156
+ @company_gen = Proc.new do |def_value, rules, index|
157
+ str = Faker::Company.name
158
+
159
+ if rules[:include_bs]
160
+ str += "\n#{Faker::Company.bs}"
161
+ end
162
+
163
+ str
164
+ end
165
+ return @company_gen
166
+ end
167
+
168
+ def name_generator
169
+ @name_gen = Proc.new do |def_value, rules, index|
170
+ Faker::Name.name
171
+ end
172
+ return @name_gen
173
+ end
174
+
175
+ # Address Generators
176
+
177
+ def city_generator
178
+ @city_gen = Proc.new do |def_value, rules, index|
179
+ Faker::Address.city
180
+ end
181
+ return @city_gen
182
+ end
183
+
184
+ def streetname_generator
185
+ @sn_gen = Proc.new do |def_value, rules, index|
186
+ Faker::Address.street_name
187
+ end
188
+ return @sn_gen
189
+ end
190
+
191
+ def state_generator
192
+ @state_gen = Proc.new do |def_value, rules, index|
193
+ supported_countries = [:us, :uk]
194
+ us_or_uk = :us
195
+ us_or_uk = :uk if rules[:country] and rules[:country].to_sym == :uk
196
+ abbr = (us_or_uk == :us and rules[:abbr]) ? "_abbr" : ""
197
+ Faker::Address.send("#{us_or_uk.to_s}_state#{abbr}")
198
+ end
199
+ return @state_gen
200
+ end
201
+
202
+ def zipcode_generator
203
+ @zip_gen = Proc.new do |def_value, rules, index|
204
+ ret_val = Faker::Address.zip_code
205
+ ret_val = Faker::Address.uk_postcode if rules[:country] and rules[:country].to_sym == :uk
206
+ ret_val
207
+ end
208
+ return @zip_gen
209
+ end
210
+
211
+
212
+ end
213
+ end
214
+ end
215
+
216
+ end
217
+ end
@@ -0,0 +1,55 @@
1
+ module Mack
2
+ module Data
3
+ class FactoryRegistryMap < Mack::Utils::RegistryMap
4
+ end
5
+ end
6
+ end
7
+
8
+ module Kernel
9
+
10
+ #
11
+ # Convenient routine to create an execution chain of factories
12
+ #
13
+ # Example:
14
+ # factories(:foo) do
15
+ # UserFactory.create(1)
16
+ # UserFactory.create(2, :diff_firstname)
17
+ # end
18
+ #
19
+ # Then to execute the chains, you'll need to call run_factories, and
20
+ # pass in the name of the chain you want to execute.
21
+ #
22
+ # Example:
23
+ # run_factories(:foo)
24
+ #
25
+ # @tag -- the name of the factory chain
26
+ # @block -- the proc to be executed later
27
+ #
28
+ def factories(tag, &block)
29
+ raise "factories: block needed" if !block_given?
30
+ fact_registry.add(tag, block)
31
+ end
32
+
33
+ #
34
+ # Run defined factory chain
35
+ #
36
+ # @see factories
37
+ # @tag -- the name of the factory chain to be run
38
+ # @return true if successful, false otherwise
39
+ def run_factories(tag)
40
+ runners = fact_registry.registered_items[tag]
41
+ return false if runners == nil
42
+
43
+ runners.each do |r|
44
+ r.call
45
+ end
46
+
47
+ return true
48
+ end
49
+
50
+ private
51
+ def fact_registry
52
+ Mack::Data::FactoryRegistryMap.instance
53
+ end
54
+
55
+ end
@@ -0,0 +1,124 @@
1
+ module Mack
2
+ module Data
3
+ #
4
+ # Add factory capability to a class.
5
+ #
6
+ # A factory is able to define which field it want to generate content for,
7
+ # define a scope for different situation, and set a custom content generator
8
+ # for field that doesn't want to use the default content generator.
9
+ #
10
+ # For more information and usage, please read README file
11
+ #
12
+ # author: Darsono Sutedja
13
+ # July 2008
14
+ #
15
+ module Factory
16
+
17
+ # make sure the data factory API is available to the class that includes it
18
+ def self.included(base)
19
+ base.extend ClassMethods
20
+ end
21
+
22
+ module ClassMethods
23
+
24
+ #
25
+ # Run the factory to produce n number of objects.
26
+ #
27
+ # Example:
28
+ # class CarFactory
29
+ # include Mack::Data::Factory
30
+ # field :name, "honda" { |def_value, rules, index| "#{def_value} #{['civic', 'accord', 'pilot'].randomize[0]}"}
31
+ # end
32
+ #
33
+ # CarFactory.create(100) #=> will produce 100 cars whose name is "honda xxx" where xxx is a random item from ['civic', 'accord', 'pilot']
34
+ #
35
+ # params:
36
+ # * num - how many objects to produce
37
+ # * scope - run the factory in a named scope
38
+ #
39
+ def create(num, scope = :default)
40
+ factory_name = self.name.underscore
41
+
42
+ # retrieve the model name from the factory class.
43
+ model_name = factory_name.gsub('_factory', '')
44
+
45
+ # if user is running custom scope, then merge the fields
46
+ # defined for that scope with the default one, before we run the factory
47
+ scoped_fields = field_manager.scopes[scope]
48
+ fields = field_manager.scopes[:default].merge(scoped_fields)
49
+
50
+ ret_arr = []
51
+
52
+ Mack::Data::RegistryMap.reset!
53
+ num.times do |i|
54
+ #puts "Creating #{model_name} ##{i+1}"
55
+ obj = model_name.camelcase.constantize.new
56
+
57
+ fields.each_pair do |k, v|
58
+ field_name = k.to_s
59
+ field_value = v.get_value(i)
60
+ assert_method(obj, "#{field_name}=", "#{model_name.camelcase} doesn't have #{field_name}= method!") do
61
+ obj.send("#{field_name}=", field_value)
62
+ end
63
+ end
64
+
65
+ assert_method(obj, "save", "#{model_name.camelcase} doesn't have save method. Data will not be saved!") do
66
+ obj.save
67
+ end
68
+
69
+ ret_arr << obj
70
+ end
71
+ Mack::Data::RegistryMap.reset!
72
+
73
+ return ret_arr[0] if ret_arr.size == 1
74
+ return ret_arr
75
+ end
76
+
77
+ #
78
+ # Define a field with its default value and rules and an optional content generator
79
+ # for this factory
80
+ #
81
+ def field(model_attrib_sym, default_value, options = {}, &block)
82
+ field_manager.add(scope, model_attrib_sym, default_value, options, &block)
83
+ end
84
+
85
+ #
86
+ # Define a scope in the factory.
87
+ # Any field defined in a scope will overwrite its cousin in the default scope.
88
+ #
89
+ def scope_for(tag)
90
+ set_scope(tag)
91
+ yield
92
+ set_scope(:default)
93
+ end
94
+
95
+ private
96
+
97
+ def scope
98
+ @current_scope ||= :default
99
+ return @current_scope
100
+ end
101
+
102
+ def set_scope(tag)
103
+ @current_scope = tag
104
+ end
105
+
106
+ def field_manager
107
+ @fm ||= Mack::Data::FieldMgr.new
108
+ return @fm
109
+ end
110
+
111
+ def assert_method(obj, meth, message)
112
+ raise "#{self.name}: assert_method: no block given" if !block_given?
113
+ if !obj.respond_to?(meth)
114
+ Mack.logger.warn(message)
115
+ else
116
+ yield
117
+ end
118
+ end
119
+
120
+ end
121
+
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,89 @@
1
+ module Mack
2
+ module Data
3
+
4
+ class RegistryMap < Mack::Utils::RegistryMap
5
+ end
6
+
7
+ class Field
8
+ attr_accessor :field_name
9
+ attr_accessor :field_value
10
+ attr_accessor :field_value_producer
11
+ attr_accessor :field_rules
12
+
13
+ def initialize(hash = {})
14
+ #puts "Inititalizing DataFactory's Field object:"
15
+
16
+ hash.each_pair do |k, v|
17
+ #puts "--> Setting #{v} to #{k}"
18
+ self.send("#{k}=", v)
19
+ end
20
+
21
+ self.field_rules = {
22
+ :immutable => false,
23
+ :length => 256,
24
+ :add_space => true,
25
+ :content => :alpha_numeric,
26
+ :null_frequency => nil
27
+ }.merge!(hash[:field_rules]) if hash[:field_rules] != nil
28
+
29
+ # transform the content type based on the given default value
30
+ if field_value.is_a?(Fixnum) or field_value.is_a?(Integer)
31
+ field_rules[:content] = :numeric
32
+ end
33
+
34
+ self.field_value_producer = Mack::Data::Factory::FieldContentGenerator.send("#{field_rules[:content]}_generator")
35
+ end
36
+
37
+ def get_value(index = 0)
38
+ # return the field_value immediately if the rule states that it's immutable
39
+ return field_value if field_rules[:immutable]
40
+
41
+ #
42
+ # if the value is a hash, then it's a relationship mapping
43
+ if field_value.is_a?(Hash)
44
+ owner = field_value.keys[0]
45
+ key = field_value[owner]
46
+ begin
47
+ owner_model = owner.to_s.camelcase.constantize
48
+ bridge = Mack::Data::Bridge.new
49
+
50
+ assoc_rules = field_rules[:assoc] || :spread
51
+ assoc_rules = :random if !([:first, :last, :random, :spread].include?(assoc_rules))
52
+ # cache the query once
53
+ if Mack::Data::RegistryMap.registered_items[self.field_name.to_sym] == nil
54
+ all_owner_models = bridge.get_all(owner_model)
55
+ Mack::Data::RegistryMap.add(self.field_name.to_sym, all_owner_models)
56
+ end
57
+
58
+ all_owner_models = Mack::Data::RegistryMap.registered_items[self.field_name.to_sym][0]
59
+
60
+ case assoc_rules
61
+ when :first
62
+ value = all_owner_models[0].send(key)
63
+ when :last
64
+ value = all_owner_models[all_owner_models.size - 1].send(key)
65
+ when :random
66
+ my_index = rand((all_owner_models.size - 1))
67
+ value = all_owner_models[my_index].send(key)
68
+ when :spread
69
+ # if index >= all_owner_models.size
70
+ # my_index = rand((all_owner_models.size - 1))
71
+ # else
72
+ # my_index = index
73
+ # end
74
+ my_index = index % all_owner_models.size
75
+ value = all_owner_models[my_index].send(key)
76
+ end
77
+
78
+ return value
79
+ rescue Exception
80
+ Mack.logger.warn "WARNING: DataFactory: field_value for #{field_name} is not set properly because data relationship defined is not correct"
81
+ end
82
+ end
83
+
84
+ # must generate random string and also respect the rules
85
+ field_value_producer.call(field_value, field_rules, index)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,28 @@
1
+ module Mack
2
+ module Data
3
+ class FieldMgr
4
+ attr_reader :scopes
5
+
6
+ def initialize
7
+ @scopes = {}
8
+ end
9
+
10
+ def add(scope, field_name, default_value, options = {}, &block)
11
+ field_list = fields(scope)
12
+ field_list[field_name] = Field.new(:field_name => field_name,
13
+ :field_value => default_value,
14
+ :field_rules => options)
15
+ field_list[field_name].field_value_producer = block if block_given?
16
+ return field_list
17
+ end
18
+
19
+ def fields(scope = :default)
20
+ if @scopes[scope].nil?
21
+ @scopes[scope] = {}
22
+ end
23
+ return @scopes[scope]
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,46 @@
1
+ module Mack
2
+ module Data
3
+
4
+ class OrmRegistry < Mack::Utils::RegistryList
5
+ end
6
+
7
+ class Bridge
8
+
9
+ def initialize
10
+ OrmRegistry.add(Mack::Data::OrmBridge::ActiveRecord.new)
11
+ OrmRegistry.add(Mack::Data::OrmBridge::DataMapper.new)
12
+ end
13
+
14
+ def get(obj, *args)
15
+ handler(obj).get(obj, *args)
16
+ end
17
+
18
+ def get_all(obj, *args)
19
+ handler(obj).get_all(obj, *args)
20
+ end
21
+
22
+ def get_first(obj, *args)
23
+ handler(obj).get_first(obj, *args)
24
+ end
25
+
26
+ def count(obj, *args)
27
+ handler(obj).count(obj, *args)
28
+ end
29
+
30
+ def save(obj, *args)
31
+ handler(obj).save(obj, *args)
32
+ end
33
+
34
+ private
35
+ def handler(obj)
36
+ OrmRegistry.registered_items.each do |i|
37
+ if i.can_handle(obj)
38
+ return i
39
+ end
40
+ end
41
+ return Mack::Data::OrmBridge::Default.new
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,34 @@
1
+ module Mack
2
+ module Data
3
+ module OrmBridge
4
+ class ActiveRecord
5
+
6
+ def can_handle(obj)
7
+ return false if !Object.const_defined?('ActiveRecord')
8
+ return obj.ancestors.include?(::ActiveRecord::Base)
9
+ end
10
+
11
+ def get(obj, *args)
12
+ obj.find(*args)
13
+ end
14
+
15
+ def get_all(obj, *args)
16
+ obj.find(:all, *args)
17
+ end
18
+
19
+ def count(obj, *args)
20
+ obj.count(*args)
21
+ end
22
+
23
+ def save(obj, *args)
24
+ obj.save
25
+ end
26
+
27
+ def get_first(obj, *args)
28
+ obj.find(:first, *args)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ module Mack
2
+ module Data
3
+ module OrmBridge
4
+ class DataMapper
5
+
6
+ def can_handle(obj)
7
+ return false if !Object.const_defined?('DataMapper')
8
+ return obj.ancestors.include?(::DataMapper::Resource)
9
+ end
10
+
11
+ def get(obj, *args)
12
+ obj.get(*args)
13
+ end
14
+
15
+ def get_all(obj, *args)
16
+ obj.all(*args)
17
+ end
18
+
19
+ def count(obj, *args)
20
+ obj.count(*args)
21
+ end
22
+
23
+ def save(obj, *args)
24
+ obj.save
25
+ end
26
+
27
+ def get_first(obj, *args)
28
+ obj.first(*args)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ module Mack
2
+ module Data
3
+ module OrmBridge
4
+ class Default
5
+
6
+ def can_handle(obj)
7
+ return true
8
+ end
9
+
10
+ def get(obj, *args)
11
+ Mack.logger.warn "Mack::Data::OrmBridge: You don't have supported orm api handler installed."
12
+ end
13
+
14
+ def get_all(obj, *args)
15
+ Mack.logger.warn "Mack::Data::OrmBridge: You don't have supported orm api handler installed."
16
+ end
17
+
18
+ def count(obj, *args)
19
+ Mack.logger.warn "Mack::Data::OrmBridge: You don't have supported orm api handler installed."
20
+ end
21
+
22
+ def save(obj, *args)
23
+ Mack.logger.warn "Mack::Data::OrmBridge: You don't have supported orm api handler installed."
24
+ end
25
+
26
+ def get_first(obj, *args)
27
+ Mack.logger.warn "Mack::Data::OrmBridge: You don't have supported orm api handler installed."
28
+ end
29
+
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ fl = File.dirname(__FILE__)
2
+
3
+ require 'faker'
4
+
5
+ [:data_factory, :field, :field_manager, :content_generator].each do |f|
6
+ require File.join(fl, 'mack-data_factory', "#{f}.rb")
7
+ end
8
+
9
+ [:kernel].each do |f|
10
+ require File.join(fl, 'mack-data_factory', 'core_extensions', "#{f}.rb")
11
+ end
12
+
13
+ [:bridge].each do |f|
14
+ require File.join(fl, 'mack-data_factory', 'orm_api_bridge', "#{f}.rb")
15
+ end
16
+
17
+ [:active_record, :data_mapper, :default].each do |f|
18
+ require File.join(fl, 'mack-data_factory', 'orm_api_bridge', 'orm', "#{f}.rb")
19
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mack-data_factory
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.1
5
+ platform: ruby
6
+ authors:
7
+ - Darsono Sutedja
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-08-04 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: faker
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.3.1
24
+ version:
25
+ description: Data factory for Mack Testing Framework
26
+ email: darsono.sutedja@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/mack-data_factory/content_generator.rb
35
+ - lib/mack-data_factory/core_extensions/kernel.rb
36
+ - lib/mack-data_factory/data_factory.rb
37
+ - lib/mack-data_factory/field.rb
38
+ - lib/mack-data_factory/field_manager.rb
39
+ - lib/mack-data_factory/orm_api_bridge/bridge.rb
40
+ - lib/mack-data_factory/orm_api_bridge/orm/active_record.rb
41
+ - lib/mack-data_factory/orm_api_bridge/orm/data_mapper.rb
42
+ - lib/mack-data_factory/orm_api_bridge/orm/default.rb
43
+ - lib/mack-data_factory.rb
44
+ - README
45
+ has_rdoc: true
46
+ homepage: http://www.mackframework.com
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project: magrathea
68
+ rubygems_version: 1.2.0
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: Data Factory
72
+ test_files: []
73
+