dibber 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +44 -12
- data/Rakefile +1 -1
- data/lib/dibber/process_log.rb +4 -0
- data/lib/dibber/seeder.rb +25 -6
- data/lib/dibber/version.rb +5 -1
- data/test/dibber/process_log_test.rb +6 -0
- data/test/dibber/seeder_test.rb +60 -1
- data/test/dibber/thing.rb +4 -54
- data/test/examples/models/admin_user.rb +5 -0
- data/test/examples/models/borough.rb +5 -0
- data/test/examples/models/category.rb +6 -0
- data/test/examples/models/disclaimer.rb +6 -0
- data/test/examples/models/fee.rb +5 -0
- data/{lib → test}/examples/process_logs.rb +1 -1
- data/{lib → test}/examples/seeds.rb +26 -11
- data/{lib → test}/examples/seeds/boroughs.yml +0 -0
- data/{lib → test}/examples/seeds/categories.yml +0 -0
- data/{lib → test}/examples/seeds/disclaimer/documents.yml +0 -0
- data/{lib → test}/examples/seeds/fees.yml +0 -0
- data/test/not_quite_active_record.rb +79 -0
- metadata +26 -8
data/README.rdoc
CHANGED
@@ -19,11 +19,11 @@ Add this to your Gemfile:
|
|
19
19
|
|
20
20
|
gem 'dibber'
|
21
21
|
|
22
|
-
=== Examples
|
22
|
+
=== Rails Examples
|
23
23
|
|
24
24
|
You have a rails app with a Thing model, and you want to seed it with some
|
25
25
|
things. Thing instances have the attributes 'name', 'colour', 'size'.
|
26
|
-
You have a YAML file '
|
26
|
+
You have a YAML file 'db/seeds/things.yml' that looks like this:
|
27
27
|
|
28
28
|
foo:
|
29
29
|
colour: red
|
@@ -36,8 +36,7 @@ You have a YAML file '/db/seeds/things.yml' that looks like this:
|
|
36
36
|
Add this to your 'db/seeds.rb'
|
37
37
|
|
38
38
|
Seeder = Dibber::Seeder
|
39
|
-
Seeder.
|
40
|
-
Seeder.new(Thing, 'things.yml').build
|
39
|
+
Seeder.seed :thing
|
41
40
|
puts Seeder.report
|
42
41
|
|
43
42
|
Then run 'rake db:seed'
|
@@ -48,23 +47,56 @@ You'll then be able to do this:
|
|
48
47
|
|
49
48
|
thing = Thing.find_by_name(:foo)
|
50
49
|
thing.colour ---> 'red'
|
50
|
+
|
51
|
+
=== Outside Rails
|
52
|
+
|
53
|
+
Dibber can be used outside of Rails, but in this case you will need to
|
54
|
+
specify the location of the seed files.
|
55
|
+
|
56
|
+
Seeder.seeds_path = "some/path/to/seeds"
|
57
|
+
|
58
|
+
You can also use this technique in Rails if you want to put your seed files
|
59
|
+
in an alternative folder to 'db/seeds'
|
51
60
|
|
52
61
|
== Report
|
53
62
|
|
54
|
-
|
55
|
-
|
63
|
+
Seeder.report outputs a report detailing start and end time, and a log of how
|
64
|
+
the number of things has changed
|
56
65
|
|
57
66
|
== Overwriting existing entries
|
58
67
|
|
59
|
-
|
60
|
-
directed to do so.
|
68
|
+
Seeder#build will not overwrite existing data unless directed to do so.
|
61
69
|
|
62
70
|
thing.update_attribute(:colour, 'black')
|
63
|
-
Seeder.
|
71
|
+
Seeder.seed :thing
|
64
72
|
thing.reload.colour ----> 'black'
|
65
73
|
|
66
|
-
Seeder.
|
74
|
+
Seeder.seed(:thing, :overwrite => true).build
|
67
75
|
thing.reload.colour ----> 'red'
|
68
76
|
|
69
|
-
|
70
|
-
|
77
|
+
|
78
|
+
== Using alternative class and field name mappings
|
79
|
+
|
80
|
+
Seeder.seed calls Seeder#build to build the objects defined in the seed files.
|
81
|
+
You can call the build method directly if your seed file names do not match
|
82
|
+
the class name:
|
83
|
+
|
84
|
+
Seeder.new(Thing, 'other_things.yml').build
|
85
|
+
|
86
|
+
== More examples
|
87
|
+
|
88
|
+
Take a look at test/examples/seeds.rb for some more usage examples.
|
89
|
+
|
90
|
+
If you clone this app, you can run this example at the project root:
|
91
|
+
|
92
|
+
ruby test/examples/seeds.rb
|
93
|
+
|
94
|
+
There is also an example of process log usage:
|
95
|
+
|
96
|
+
ruby test/examples/process_logs.rb
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
data/Rakefile
CHANGED
data/lib/dibber/process_log.rb
CHANGED
data/lib/dibber/seeder.rb
CHANGED
@@ -5,6 +5,13 @@ module Dibber
|
|
5
5
|
class Seeder
|
6
6
|
attr_accessor :klass, :file, :attribute_method, :name_method, :overwrite
|
7
7
|
|
8
|
+
def self.seed(name, args = {})
|
9
|
+
class_name = name.to_s.strip.classify
|
10
|
+
new_klass = (/\A\w+(::\w+)+\Z/ =~ class_name) ? eval(class_name) : Kernel.const_get(class_name)
|
11
|
+
new_file = "#{name.to_s.pluralize}.yml"
|
12
|
+
new(new_klass, new_file, args).build
|
13
|
+
end
|
14
|
+
|
8
15
|
def self.process_log
|
9
16
|
@process_log || start_process_log
|
10
17
|
end
|
@@ -20,7 +27,10 @@ module Dibber
|
|
20
27
|
end
|
21
28
|
|
22
29
|
def self.monitor(klass)
|
23
|
-
|
30
|
+
log_name = klass.to_s.tableize.to_sym
|
31
|
+
unless process_log.exists?(log_name)
|
32
|
+
process_log.start(log_name, "#{klass}.count")
|
33
|
+
end
|
24
34
|
end
|
25
35
|
|
26
36
|
def self.objects_from(file)
|
@@ -28,15 +38,13 @@ module Dibber
|
|
28
38
|
end
|
29
39
|
|
30
40
|
def self.seeds_path
|
31
|
-
@seeds_path || raise_no_seeds_path_error
|
41
|
+
@seeds_path || try_to_guess_seeds_path || raise_no_seeds_path_error
|
32
42
|
end
|
33
43
|
|
34
44
|
def self.seeds_path=(path)
|
35
|
-
|
36
|
-
@seeds_path = path
|
45
|
+
@seeds_path = add_trailing_slash_to(path)
|
37
46
|
end
|
38
47
|
|
39
|
-
|
40
48
|
def initialize(klass, file, args = {})
|
41
49
|
@klass = klass
|
42
50
|
@file = file
|
@@ -47,8 +55,8 @@ module Dibber
|
|
47
55
|
end
|
48
56
|
|
49
57
|
def build
|
50
|
-
start_log
|
51
58
|
check_objects_exist
|
59
|
+
start_log
|
52
60
|
objects.each do |name, attributes|
|
53
61
|
object = klass.send(retrieval_method, name)
|
54
62
|
if overwrite or object.new_record?
|
@@ -79,5 +87,16 @@ module Dibber
|
|
79
87
|
"find_or_initialize_by_#{name_method}"
|
80
88
|
end
|
81
89
|
|
90
|
+
def self.try_to_guess_seeds_path
|
91
|
+
path = File.expand_path('db/seeds', Rails.root) if defined? Rails
|
92
|
+
add_trailing_slash_to(path)
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
def self.add_trailing_slash_to(path = nil)
|
97
|
+
path = path + '/' if path and path !~ /\/$/
|
98
|
+
path
|
99
|
+
end
|
100
|
+
|
82
101
|
end
|
83
102
|
end
|
data/lib/dibber/version.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
module Dibber
|
2
|
-
VERSION = "0.
|
2
|
+
VERSION = "0.3.0"
|
3
3
|
end
|
4
4
|
|
5
5
|
# History
|
6
6
|
# =======
|
7
|
+
# 0.3.0 Adds seed method
|
8
|
+
# Allows seeding to be carried out via Dibber::Seeder.seed(:thing).
|
9
|
+
# Also tidies up examples
|
10
|
+
#
|
7
11
|
# 0.2.2 Minor bug fix. There was an error in the example. Also a small bit
|
8
12
|
# of house keeping (adding license to gemspec, and removing Gemfile.lock
|
9
13
|
# from repository.
|
@@ -44,5 +44,11 @@ module Dibber
|
|
44
44
|
expected = ['No finish was 1, now 1.']
|
45
45
|
assert_equal(expected, @process_log.report)
|
46
46
|
end
|
47
|
+
|
48
|
+
def test_exists_method
|
49
|
+
assert !@process_log.exists?(:one), "There should not be a log for :one yet"
|
50
|
+
test_one
|
51
|
+
assert @process_log.exists?(:one), "There should be log for :one"
|
52
|
+
end
|
47
53
|
end
|
48
54
|
end
|
data/test/dibber/seeder_test.rb
CHANGED
@@ -9,7 +9,7 @@ module Dibber
|
|
9
9
|
class SeederTest < Test::Unit::TestCase
|
10
10
|
|
11
11
|
def setup
|
12
|
-
Seeder.seeds_path = File.join(File.dirname(__FILE__),'seeds')
|
12
|
+
Seeder.seeds_path = File.join(File.dirname(__FILE__), 'seeds')
|
13
13
|
end
|
14
14
|
|
15
15
|
def teardown
|
@@ -121,6 +121,65 @@ module Dibber
|
|
121
121
|
assert_equal([foo, bar], Thing.saved)
|
122
122
|
assert_equal({'title' => 'one'}, foo.attributes)
|
123
123
|
end
|
124
|
+
|
125
|
+
def test_seed
|
126
|
+
assert_equal(0, Thing.count)
|
127
|
+
Seeder.seed(:things)
|
128
|
+
assert_equal(2, Thing.count)
|
129
|
+
foo = Thing.find_or_initialize_by_name(:foo)
|
130
|
+
bar = Thing.find_or_initialize_by_name(:bar)
|
131
|
+
assert_equal([foo, bar], Thing.saved)
|
132
|
+
assert_equal({'title' => 'one'}, foo.attributes)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_seed_with_alternative_name_method
|
136
|
+
Seeder.seed(:things, :name_method => 'other_method')
|
137
|
+
assert_equal(2, Thing.count)
|
138
|
+
foo = Thing.find_or_initialize_by_other_method(:foo)
|
139
|
+
bar = Thing.find_or_initialize_by_other_method(:bar)
|
140
|
+
assert_equal([foo, bar], Thing.saved)
|
141
|
+
assert_equal({'title' => 'one'}, foo.attributes)
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_seed_with_non_existent_class
|
145
|
+
assert_raise NameError do
|
146
|
+
Seeder.seed(:non_existent_class)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_seed_with_non_existent_seed_file
|
151
|
+
no_file_found_error = Errno::ENOENT
|
152
|
+
assert_raise no_file_found_error do
|
153
|
+
Seeder.seed(:array)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_seeds_path_with_none_set
|
158
|
+
Seeder.seeds_path = nil
|
159
|
+
assert_raise RuntimeError do
|
160
|
+
Seeder.seeds_path
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_process_log_not_reset_by_second_seed_process_on_same_class
|
165
|
+
Seeder.seed(:things)
|
166
|
+
original_start = Seeder.process_log.raw[:things][:start]
|
167
|
+
Seeder.seed(:things)
|
168
|
+
assert_equal original_start, Seeder.process_log.raw[:things][:start]
|
169
|
+
end
|
170
|
+
|
171
|
+
module DummyRails
|
172
|
+
def self.root
|
173
|
+
'/some/path'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_seeds_path_if_Rails_exists
|
178
|
+
Dibber.const_set :Rails, DummyRails
|
179
|
+
Seeder.seeds_path = nil
|
180
|
+
assert_equal '/some/path/db/seeds/', Seeder.seeds_path
|
181
|
+
Dibber.send(:remove_const, :Rails)
|
182
|
+
end
|
124
183
|
|
125
184
|
|
126
185
|
private
|
data/test/dibber/thing.rb
CHANGED
@@ -1,55 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
def initialize(name = nil)
|
6
|
-
@name = name.to_s if name
|
7
|
-
self.class.members << self
|
8
|
-
end
|
9
|
-
|
10
|
-
def save
|
11
|
-
self.class.saved << self if new_record?
|
12
|
-
true
|
13
|
-
end
|
14
|
-
|
15
|
-
def new_record?
|
16
|
-
!self.class.saved.include? self
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.find_or_initialize_by_name(name)
|
20
|
-
existing = members.select{|m| m.name == name.to_s}
|
21
|
-
if existing.empty?
|
22
|
-
new(name)
|
23
|
-
else
|
24
|
-
existing.first
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.find_or_initialize_by_other_method(data)
|
29
|
-
existing = members.select{|m| m.other_method == data.to_s}
|
30
|
-
if existing.empty?
|
31
|
-
thing = new
|
32
|
-
thing.other_method = data.to_s
|
33
|
-
thing
|
34
|
-
else
|
35
|
-
existing.first
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.members
|
40
|
-
@members ||= []
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.count
|
44
|
-
members.length
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.saved
|
48
|
-
@saved ||= []
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.clear_all
|
52
|
-
@members = []
|
53
|
-
@saved = []
|
54
|
-
end
|
1
|
+
require_relative '../not_quite_active_record'
|
2
|
+
|
3
|
+
class Thing < NotQuiteActiveRecord
|
4
|
+
attr_accessor :other_method
|
55
5
|
end
|
@@ -1,7 +1,13 @@
|
|
1
|
+
require_relative '../../lib/dibber'
|
2
|
+
|
3
|
+
models = %w{borough admin_user fee disclaimer category}
|
4
|
+
models.each {|model| require_relative "models/#{model}"}
|
5
|
+
|
6
|
+
|
1
7
|
Seeder = Dibber::Seeder
|
2
8
|
|
3
9
|
# Set up the path to seed YAML files
|
4
|
-
Seeder.seeds_path =
|
10
|
+
Seeder.seeds_path = File.expand_path('seeds', File.dirname(__FILE__))
|
5
11
|
|
6
12
|
# Example 1. Seeder is used to monitor the process
|
7
13
|
# and grab the attributes from the YAML file
|
@@ -30,22 +36,31 @@ Seeder.new(Fee, 'fees.yml').build
|
|
30
36
|
# Example 4. Seeder using an alternative name field
|
31
37
|
Seeder.new(Fee, 'fees.yml', :name_method => :title).build
|
32
38
|
|
33
|
-
# Example 5.
|
39
|
+
# Example 5. If the seed file's name is the lower case plural of the class name
|
40
|
+
# you can use the seed method:
|
41
|
+
Seeder.seed(:fee)
|
42
|
+
|
43
|
+
# Example 6. Seeder working with a name-spaced object
|
34
44
|
Seeder.new(Disclaimer::Document, 'disclaimer/documents.yml').build
|
35
45
|
|
36
|
-
# Example
|
37
|
-
|
46
|
+
# Example 7. You can also use the seed method with name-spaced objects.
|
47
|
+
# In this case the seed files need to be in a name-spaced path (see previous
|
48
|
+
# example)
|
49
|
+
Seeder.seed('disclaimer/document')
|
50
|
+
|
51
|
+
# Example 8. Seeder using values in the yaml file to set a single field
|
52
|
+
Seeder.seed(:category, 'description')
|
38
53
|
|
39
|
-
# Example
|
40
|
-
Seeder.
|
41
|
-
|
42
|
-
'categories.yml',
|
54
|
+
# Example 9. Seeder using alternative name and attributes fields
|
55
|
+
Seeder.seed(
|
56
|
+
:category,
|
43
57
|
:name_method => :title,
|
44
58
|
:attributes_method => :description
|
45
|
-
)
|
59
|
+
)
|
46
60
|
|
47
|
-
# You can also access Seeders attached process log, and set up a
|
48
|
-
|
61
|
+
# Example 10. You can also access Seeders attached process log, and set up a
|
62
|
+
# custom log
|
63
|
+
Seeder.process_log.start('Time to end of report', 'Time.now')
|
49
64
|
|
50
65
|
# Output a report showing how the numbers of each type of object
|
51
66
|
# have changed through the process. Also has a log of start and end time.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Mock ActiveRecord::Base
|
2
|
+
class NotQuiteActiveRecord
|
3
|
+
attr_reader :name
|
4
|
+
attr_accessor :attributes
|
5
|
+
|
6
|
+
def initialize(name = nil)
|
7
|
+
@name = name.to_s if name
|
8
|
+
self.class.members << self
|
9
|
+
end
|
10
|
+
|
11
|
+
def save
|
12
|
+
self.class.saved << self if new_record?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def new_record?
|
17
|
+
!self.class.saved.include? self
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find_or_initialize_by_name(name)
|
21
|
+
existing = members.select{|m| m.name == name.to_s}
|
22
|
+
if existing.empty?
|
23
|
+
new(name)
|
24
|
+
else
|
25
|
+
existing.first
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.find_or_initialize_by_title(title)
|
30
|
+
existing = members.select{|m| m.title == title.to_s}
|
31
|
+
if existing.empty?
|
32
|
+
fee = new
|
33
|
+
fee.title = title
|
34
|
+
fee
|
35
|
+
else
|
36
|
+
existing.first
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.find_or_create_by_name(name)
|
41
|
+
find_or_initialize_by_name(name).save
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.find_or_initialize_by_other_method(data)
|
45
|
+
existing = members.select{|m| m.other_method == data.to_s}
|
46
|
+
if existing.empty?
|
47
|
+
thing = new
|
48
|
+
thing.other_method = data.to_s
|
49
|
+
thing
|
50
|
+
else
|
51
|
+
existing.first
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.exists?(hash)
|
56
|
+
!members.select{|m| m.send(hash.first[0]) == hash.first[1].to_s}.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.create!(hash)
|
60
|
+
new(hash).save
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.members
|
64
|
+
@members ||= []
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.count
|
68
|
+
members.length
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.saved
|
72
|
+
@saved ||= []
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.clear_all
|
76
|
+
@members = []
|
77
|
+
@saved = []
|
78
|
+
end
|
79
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dibber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: active_support
|
@@ -35,12 +35,6 @@ executables: []
|
|
35
35
|
extensions: []
|
36
36
|
extra_rdoc_files: []
|
37
37
|
files:
|
38
|
-
- lib/examples/process_logs.rb
|
39
|
-
- lib/examples/seeds/boroughs.yml
|
40
|
-
- lib/examples/seeds/disclaimer/documents.yml
|
41
|
-
- lib/examples/seeds/fees.yml
|
42
|
-
- lib/examples/seeds/categories.yml
|
43
|
-
- lib/examples/seeds.rb
|
44
38
|
- lib/dibber.rb
|
45
39
|
- lib/dibber/version.rb
|
46
40
|
- lib/dibber/process_log.rb
|
@@ -48,6 +42,18 @@ files:
|
|
48
42
|
- MIT-LICENSE
|
49
43
|
- Rakefile
|
50
44
|
- README.rdoc
|
45
|
+
- test/examples/process_logs.rb
|
46
|
+
- test/examples/models/admin_user.rb
|
47
|
+
- test/examples/models/disclaimer.rb
|
48
|
+
- test/examples/models/category.rb
|
49
|
+
- test/examples/models/borough.rb
|
50
|
+
- test/examples/models/fee.rb
|
51
|
+
- test/examples/seeds/boroughs.yml
|
52
|
+
- test/examples/seeds/disclaimer/documents.yml
|
53
|
+
- test/examples/seeds/fees.yml
|
54
|
+
- test/examples/seeds/categories.yml
|
55
|
+
- test/examples/seeds.rb
|
56
|
+
- test/not_quite_active_record.rb
|
51
57
|
- test/dibber/seeder_test.rb
|
52
58
|
- test/dibber/thing.rb
|
53
59
|
- test/dibber/process_log_test.rb
|
@@ -80,6 +86,18 @@ signing_key:
|
|
80
86
|
specification_version: 3
|
81
87
|
summary: Tool for seeding database from YAML.
|
82
88
|
test_files:
|
89
|
+
- test/examples/process_logs.rb
|
90
|
+
- test/examples/models/admin_user.rb
|
91
|
+
- test/examples/models/disclaimer.rb
|
92
|
+
- test/examples/models/category.rb
|
93
|
+
- test/examples/models/borough.rb
|
94
|
+
- test/examples/models/fee.rb
|
95
|
+
- test/examples/seeds/boroughs.yml
|
96
|
+
- test/examples/seeds/disclaimer/documents.yml
|
97
|
+
- test/examples/seeds/fees.yml
|
98
|
+
- test/examples/seeds/categories.yml
|
99
|
+
- test/examples/seeds.rb
|
100
|
+
- test/not_quite_active_record.rb
|
83
101
|
- test/dibber/seeder_test.rb
|
84
102
|
- test/dibber/thing.rb
|
85
103
|
- test/dibber/process_log_test.rb
|