dummy 0.6 → 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +2 -52
- data/README.md +11 -55
- data/lib/dummy/lorem.rb +1 -1
- data/lib/dummy.rb +1 -2
- metadata +7 -24
- data/lib/generators/dummy_generator.rb +0 -194
- data/lib/generators/templates/dummy.rake +0 -13
data/CHANGELOG.md
CHANGED
@@ -1,55 +1,5 @@
|
|
1
|
-
## 0.
|
1
|
+
## 0.9 (August 10, 2010)
|
2
2
|
|
3
3
|
Features:
|
4
|
-
-
|
5
|
-
|
6
|
-
|
7
|
-
## 0.2 (July 17, 2010)
|
8
|
-
|
9
|
-
Features:
|
10
|
-
- moved data generation into a generator
|
11
|
-
- added growth-ratio and base-amount options
|
12
|
-
|
13
|
-
|
14
|
-
## 0.3 (July 21, 2010)
|
15
|
-
|
16
|
-
Features:
|
17
|
-
- added rake task to import the generated dummy data in the target application
|
18
|
-
|
19
|
-
|
20
|
-
## 0.4 (July 24, 2010)
|
21
|
-
|
22
|
-
Features:
|
23
|
-
- improved data generation (which tries to be smart, RIP lorem ipsum)
|
24
|
-
|
25
|
-
|
26
|
-
## 0.5 (July 24, 2010)
|
27
|
-
|
28
|
-
Features:
|
29
|
-
- added tests for the data generators and rails generator
|
30
|
-
- small improvements
|
31
|
-
- added documentation
|
32
|
-
|
33
|
-
Fixes:
|
34
|
-
- various minor bugs
|
35
|
-
|
36
|
-
## 0.5.1 (July 29, 2010)
|
37
|
-
|
38
|
-
Fixes:
|
39
|
-
- fixed a bug where magic integers were being returned as strings
|
40
|
-
|
41
|
-
## 0.5.2 (July 30, 2010)
|
42
|
-
|
43
|
-
Features:
|
44
|
-
- added option to manually configure the amount of records to generate for each model
|
45
|
-
|
46
|
-
## 0.6 (July 31, 2010)
|
47
|
-
|
48
|
-
Features:
|
49
|
-
- added option to define the output folder where the YAML files are placed
|
50
|
-
|
51
|
-
Fixes:
|
52
|
-
- Removed unused core extensions (for now)
|
53
|
-
- fixed some outdated tests
|
54
|
-
|
4
|
+
- cleverly generating dummy data (functionality split up from old project)
|
55
5
|
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# Dummy
|
2
2
|
|
3
|
-
Dummy generates dummy data
|
3
|
+
Dummy generates dummy data in a clever way.
|
4
4
|
|
5
5
|
## Description
|
6
6
|
|
7
|
-
Dummy
|
7
|
+
Dummy can generate a lot of dummy data from company names to postal codes. While it allows you to specifically request a type of information, it can also try to determine what you're looking for given a couple of parameters.
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
@@ -12,28 +12,7 @@ $ gem install dummy
|
|
12
12
|
|
13
13
|
## Usage
|
14
14
|
|
15
|
-
|
16
|
-
gem "dummy"
|
17
|
-
|
18
|
-
Now you have access to the generator:
|
19
|
-
rails generate dummy:data
|
20
|
-
|
21
|
-
You can change the base amount of records and the growth ratio (what these mean exactly is explained latter on):
|
22
|
-
rails generate dummy:data --base-amount 5 --growth-ratio 1.5
|
23
|
-
|
24
|
-
Also, you can manually define the amount of records to generate for each model (or just accept the defaults):
|
25
|
-
rails generate dummy:data --manual-amounts
|
26
|
-
|
27
|
-
And you can manually set the output folder for the YAML files (which defaults to test/dummy/data):
|
28
|
-
rails generate dummy:data --output-folder test/awesome_fixtures
|
29
|
-
|
30
|
-
|
31
|
-
The fixtures are stored in _test/dummy/_ while a rake file is placed in _lib/tasks/dummy.rake_. It allows you to import the generated data into the database:
|
32
|
-
RAILS_ENV="dummy" rake dummy:data:import
|
33
|
-
|
34
|
-
Don't forget to change RAILS_ENV to whatever is appropriate for you (and is configured under databases.yml). Your database doesn't need to be empty.
|
35
|
-
|
36
|
-
Another less conventional way of using dummy is to directly use its magic data generation:
|
15
|
+
To ask for cleverly generated dummy data:
|
37
16
|
Dummy.magic_data(field, type)
|
38
17
|
|
39
18
|
Example:
|
@@ -44,43 +23,20 @@ Example:
|
|
44
23
|
Dummy.magic_data("state", :string) => "Louisiana"
|
45
24
|
Dummy.magic_data("lat", :float) => -86.718683637
|
46
25
|
Dummy.magic_data("phone", :integer) => 9462876293
|
47
|
-
|
48
|
-
|
49
|
-
## More information
|
50
|
-
|
51
|
-
### Smart data
|
52
|
-
|
53
|
-
Dummy tries to understand your database columns and generates data accordingly, instead of dumping "Lorem ipsum" all over the place.
|
54
|
-
|
55
|
-
For instance, if you have a field called _company\_name_, it will generate a company name. If you have a field called _awesome\_postal\_code_, it will generate a valid ZIP Code. If you have a field called _longitude_, it will generate a valid longitude. And so on. You get the picture.
|
56
|
-
|
57
|
-
Dummy cares about associations. It will create random associations between the automatically generated records.
|
58
|
-
|
59
|
-
### Smart amounts of data
|
60
|
-
|
61
|
-
Dummy is aware that the amount of records that each model has in real world applications is different. For this reason, it will analyze your model associations to try to make a somewhat accurate estimation of the expected amount of records.
|
62
|
-
|
63
|
-
To illustrate this, consider an application with models for _Child_, _Parent_ and _GrandParent_. If the base amount is 10, the growth ratio is 2.0, and the models look like the following:
|
64
|
-
|
65
|
-
class GrandParent < ActiveRecord::Base
|
66
|
-
has_many :parents
|
67
|
-
end
|
68
26
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
27
|
+
You can also use its submodules for specific data:
|
28
|
+
Dummy::Name.first_name => "Muhammad"
|
29
|
+
Dummy::Internet.url => "https://david.grady.biz"
|
30
|
+
Dummy::Address.street_address => "10273 Delaney Extensions"
|
73
31
|
|
74
|
-
|
75
|
-
belongs_to :parent
|
76
|
-
end`
|
32
|
+
Have a look in the rdoc for all available generators.
|
77
33
|
|
78
|
-
|
34
|
+
## More information
|
79
35
|
|
80
36
|
### Caveats
|
81
37
|
|
82
38
|
Dummy has a few caveats which are on the TODO list. Those are:
|
83
|
-
|
84
|
-
* It will
|
39
|
+
|
40
|
+
* It is an English speaking gem. It will not be smart at all if your column is named _telefone_ (Portuguese for _phone_) or if you want a zip code from outside the US.
|
85
41
|
|
86
42
|
Copyright (c) 2010 Gonçalo Silva
|
data/lib/dummy/lorem.rb
CHANGED
data/lib/dummy.rb
CHANGED
@@ -7,11 +7,10 @@ require "dummy/lorem"
|
|
7
7
|
require "dummy/name"
|
8
8
|
require "dummy/phone_number"
|
9
9
|
require "dummy/geolocation"
|
10
|
-
require "generators/dummy_generator"
|
11
10
|
|
12
11
|
module Dummy
|
13
12
|
class << self
|
14
|
-
|
13
|
+
|
15
14
|
def magic_data(field, type)
|
16
15
|
case type
|
17
16
|
when :string, :text then magic_string(field, type)
|
metadata
CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
version: "0.
|
7
|
+
- 9
|
8
|
+
version: "0.9"
|
9
9
|
platform: ruby
|
10
10
|
authors:
|
11
11
|
- "Gon\xC3\xA7alo Silva"
|
@@ -13,26 +13,11 @@ autorequire:
|
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
15
|
|
16
|
-
date: 2010-
|
16
|
+
date: 2010-08-11 00:00:00 +01:00
|
17
17
|
default_executable:
|
18
|
-
dependencies:
|
19
|
-
|
20
|
-
|
21
|
-
prerelease: false
|
22
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
-
none: false
|
24
|
-
requirements:
|
25
|
-
- - ">="
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
segments:
|
28
|
-
- 3
|
29
|
-
- 0
|
30
|
-
- 0
|
31
|
-
- rc
|
32
|
-
version: 3.0.0.rc
|
33
|
-
type: :runtime
|
34
|
-
version_requirements: *id001
|
35
|
-
description: Generates consistent fake data and allows you to insert it to the database
|
18
|
+
dependencies: []
|
19
|
+
|
20
|
+
description: A Ruby library to generate clever dummy data
|
36
21
|
email:
|
37
22
|
- goncalossilva@gmail.com
|
38
23
|
executables: []
|
@@ -52,9 +37,7 @@ files:
|
|
52
37
|
- lib/dummy/internet.rb
|
53
38
|
- lib/dummy/geolocation.rb
|
54
39
|
- lib/dummy/phone_number.rb
|
55
|
-
- lib/generators/dummy_generator.rb
|
56
40
|
- lib/dummy.rb
|
57
|
-
- lib/generators/templates/dummy.rake
|
58
41
|
- LICENSE
|
59
42
|
- README.md
|
60
43
|
- CHANGELOG.md
|
@@ -91,6 +74,6 @@ rubyforge_project: dummy
|
|
91
74
|
rubygems_version: 1.3.7
|
92
75
|
signing_key:
|
93
76
|
specification_version: 3
|
94
|
-
summary: Generates
|
77
|
+
summary: Generates dummy data
|
95
78
|
test_files: []
|
96
79
|
|
@@ -1,194 +0,0 @@
|
|
1
|
-
require "yaml"
|
2
|
-
require "active_support"
|
3
|
-
require "active_record"
|
4
|
-
require "rails/generators"
|
5
|
-
|
6
|
-
module Dummy
|
7
|
-
class DataGenerator < Rails::Generators::Base
|
8
|
-
def self.source_root
|
9
|
-
@source_root ||= File.expand_path("../templates", __FILE__)
|
10
|
-
end
|
11
|
-
|
12
|
-
class_option :base_amount, :type => :numeric, :default => 10,
|
13
|
-
:desc => "The base amount of records to generate for each model."
|
14
|
-
class_option :growth_ratio, :type => :numeric, :default => 2.0,
|
15
|
-
:desc => "The growth ratio of each model, according to its associations."
|
16
|
-
class_option :manual_amounts, :type => :boolean, :default => false,
|
17
|
-
:desc => "Manually set the amount of records for each model."
|
18
|
-
class_option :output_folder, :type => :string, :default => "test/dummy/data",
|
19
|
-
:desc => "Folder to use when outputting the resulting YAML files."
|
20
|
-
|
21
|
-
def install_dummy
|
22
|
-
initialize_application
|
23
|
-
generate_dummy_data
|
24
|
-
copy_rake_file
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def initialize_application
|
30
|
-
require File.expand_path("#{Rails.root}/config/environment.rb")
|
31
|
-
say_status :successful, "initialize Rails application"
|
32
|
-
end
|
33
|
-
|
34
|
-
def generate_dummy_data
|
35
|
-
get_table_names
|
36
|
-
gather_associations
|
37
|
-
predict_record_amounts
|
38
|
-
generate_and_write_data
|
39
|
-
end
|
40
|
-
|
41
|
-
def get_table_names
|
42
|
-
@models = Hash.new
|
43
|
-
Dir["app/models/*.rb"].each do |full_path|
|
44
|
-
model = File.basename(full_path).chomp(File.extname(full_path)).camelcase.constantize
|
45
|
-
@models.merge!({model => {
|
46
|
-
:record_amount => 0, :associations => []
|
47
|
-
}}) if model.respond_to?(:columns)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def gather_associations
|
52
|
-
@models.each_key do |model|
|
53
|
-
model_symbol = model.to_s.underscore.pluralize.to_sym
|
54
|
-
associations = model.reflect_on_all_associations(:belongs_to)
|
55
|
-
|
56
|
-
associations.each do |assoc|
|
57
|
-
assoc_name = assoc.name.to_s.camelcase
|
58
|
-
assoc_options = assoc.options
|
59
|
-
|
60
|
-
if assoc_options.empty?
|
61
|
-
@models[model][:associations].push({
|
62
|
-
:model => assoc_name.constantize,
|
63
|
-
:foreign_key => "#{assoc_name.underscore}_id"
|
64
|
-
})
|
65
|
-
elsif assoc_options.has_key?(:class_name) and assoc_options.has_key?(:foreign_key)
|
66
|
-
@models[model][:associations].push({
|
67
|
-
:model => assoc_options[:class_name].constantize, # TODO: handle class_name
|
68
|
-
:foreign_key => assoc_options[:foreign_key]
|
69
|
-
})
|
70
|
-
else
|
71
|
-
next
|
72
|
-
end
|
73
|
-
|
74
|
-
assoc_model = @models[model][:associations].last[:model]
|
75
|
-
assoc_reflections = assoc_model.reflect_on_all_associations(:has_one)
|
76
|
-
@models[model][:associations].pop if assoc_reflections.map(&:name).include?(model_symbol)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def predict_record_amounts
|
82
|
-
models = @models.dup
|
83
|
-
models.each do |model, info|
|
84
|
-
predict_record_amount(model, info, models, [])
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def predict_record_amount(model, info, models, stacked_models)
|
89
|
-
info[:associations].each do |assoc|
|
90
|
-
next if stacked_models.include?(assoc[:model])
|
91
|
-
|
92
|
-
if model != assoc[:model]
|
93
|
-
stacked_models << assoc[:model]
|
94
|
-
predict_record_amount(assoc[:model], @models[assoc[:model]], models, stacked_models)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
amount = options.base_amount
|
99
|
-
if not info[:associations].empty?
|
100
|
-
amount = info[:associations].map do |assoc|
|
101
|
-
@models[assoc[:model]][:record_amount]
|
102
|
-
end.max*options.growth_ratio # **info[:associations].size
|
103
|
-
end
|
104
|
-
|
105
|
-
if options.manual_amounts
|
106
|
-
user_defined = ask("Number of records for #{model} (default: #{amount}): ")
|
107
|
-
amount = user_defined unless user_defined.empty?
|
108
|
-
end
|
109
|
-
|
110
|
-
@models[model][:record_amount] = amount.to_i
|
111
|
-
stacked_models.delete(model)
|
112
|
-
models.delete(model)
|
113
|
-
end
|
114
|
-
|
115
|
-
def generate_and_write_data
|
116
|
-
empty_directory options.output_folder
|
117
|
-
data = Hash.new
|
118
|
-
|
119
|
-
@models.each do |model, info|
|
120
|
-
name = model.to_s.underscore
|
121
|
-
|
122
|
-
(0..info[:record_amount]-1).each do |num|
|
123
|
-
key_value = Hash.new
|
124
|
-
fixture_data = Hash.new
|
125
|
-
|
126
|
-
model.columns.each do |column|
|
127
|
-
key_value = generate_record_data(name, info, column)
|
128
|
-
fixture_data.merge!(key_value) unless key_value.nil?
|
129
|
-
end
|
130
|
-
|
131
|
-
data[model.table_name] = Hash.new if data[model.table_name].nil?
|
132
|
-
data[model.table_name].merge!({ "#{name}_#{num}" => fixture_data })
|
133
|
-
end
|
134
|
-
|
135
|
-
say_status :successful, "generate #{info[:record_amount]} records for '#{name}'"
|
136
|
-
end
|
137
|
-
|
138
|
-
data.each do |name, fixtures|
|
139
|
-
content = "# '#{name}' data generated automatically by dummy at #{Time.now.strftime("%H:%M %m/%d/%Y")} (#{fixtures.size} records).\n"
|
140
|
-
|
141
|
-
content << YAML.dump(fixtures)
|
142
|
-
|
143
|
-
create_file "#{options.output_folder}/#{name}.yml", content
|
144
|
-
end
|
145
|
-
say_status :successful, "store fixtures"
|
146
|
-
end
|
147
|
-
|
148
|
-
def generate_record_data(name, info, column)
|
149
|
-
column_name = column.name
|
150
|
-
if(column_name =~ /_at$/ and column.type == :datetime) or column_name == "id"
|
151
|
-
return
|
152
|
-
end
|
153
|
-
|
154
|
-
associated_model = associated_class_name(info, column_name)
|
155
|
-
|
156
|
-
if associated_model
|
157
|
-
val = generate_association_data(associated_model)
|
158
|
-
column_name.gsub!(/_id$/, "")
|
159
|
-
else
|
160
|
-
val = generate_regular_data(column)
|
161
|
-
end
|
162
|
-
|
163
|
-
{column_name => val}
|
164
|
-
end
|
165
|
-
|
166
|
-
def associated_class_name(info, name)
|
167
|
-
info[:associations].each do |assoc|
|
168
|
-
return assoc[:model] if assoc[:foreign_key] == name
|
169
|
-
end
|
170
|
-
false
|
171
|
-
end
|
172
|
-
|
173
|
-
def generate_association_data(associated_model)
|
174
|
-
random_record_num = rand(@models[associated_model][:record_amount])
|
175
|
-
"#{associated_model.to_s.underscore}_#{random_record_num}"
|
176
|
-
end
|
177
|
-
|
178
|
-
def generate_regular_data(column)
|
179
|
-
val = Dummy.magic_data(column.name, column.type)
|
180
|
-
|
181
|
-
if val
|
182
|
-
val
|
183
|
-
else
|
184
|
-
say_status :failed, "data generation for '#{column.name}' with type '#{column.type.to_s.downcase}'", :red
|
185
|
-
""
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def copy_rake_file
|
190
|
-
template "dummy.rake", "lib/tasks/dummy.rake"
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'active_record/fixtures'
|
2
|
-
|
3
|
-
namespace :dummy do
|
4
|
-
namespace :data do
|
5
|
-
desc "Load the generated dummy data into the current environment's database."
|
6
|
-
task :import => :environment do
|
7
|
-
Fixtures.reset_cache
|
8
|
-
fixtures_folder = File.join(Rails.root, "<%= options.output_folder %>")
|
9
|
-
fixtures = Dir[File.join(fixtures_folder, '*.yml')].map {|f| File.basename(f, '.yml') }
|
10
|
-
Fixtures.create_fixtures(fixtures_folder, fixtures)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|