dibber 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +44 -1
- data/lib/dibber/seeder.rb +21 -7
- data/lib/dibber/thing.rb +51 -0
- data/lib/dibber/version.rb +1 -1
- data/lib/examples/seeds.rb +18 -6
- data/test/dibber/seeder_test.rb +112 -0
- data/test/dibber/seeds/empty.yml +2 -0
- data/test/dibber/seeds/things.yml +5 -0
- data/test/dibber/thing_test.rb +81 -0
- metadata +28 -3
data/README.rdoc
CHANGED
@@ -5,10 +5,53 @@ A set of tools to tidy up rails seeds.rb files.
|
|
5
5
|
Dibber has two compoments:
|
6
6
|
|
7
7
|
=== Seeder
|
8
|
+
|
8
9
|
Seeder is designed to simplify the process of pulling attributes from
|
9
10
|
YAML files, and populating ActiveRecord objects with those attributes.
|
10
11
|
|
11
12
|
=== ProcessLog
|
13
|
+
|
12
14
|
ProcessLog provides Seeder with a simple before and after reporting tool.
|
13
15
|
|
14
|
-
|
16
|
+
=== Installation
|
17
|
+
|
18
|
+
Add this to your Gemfile:
|
19
|
+
|
20
|
+
gem 'dibber'
|
21
|
+
|
22
|
+
=== Examples
|
23
|
+
|
24
|
+
You have a rails app with a Thing model, and you want to seed it with some
|
25
|
+
things. Thing instances have the attributes 'name', 'colour', 'size'.
|
26
|
+
You have a YAML file '/db/seeds/things.yml' that looks like this:
|
27
|
+
|
28
|
+
foo:
|
29
|
+
colour: red
|
30
|
+
size: large
|
31
|
+
|
32
|
+
bar:
|
33
|
+
colour: blue
|
34
|
+
size: small
|
35
|
+
|
36
|
+
Add this to your 'db/seeds.rb'
|
37
|
+
|
38
|
+
Seeder = Dibber::Seeder
|
39
|
+
Seeder.seeds_path = "#{Rails.root}/db/seeds"
|
40
|
+
Seeder.new(Thing, 'things.yml').build
|
41
|
+
|
42
|
+
Then run 'rake db:seed'
|
43
|
+
|
44
|
+
Seeder will create two new things (unless things with the names 'foo' or
|
45
|
+
'bar' already exist, in which case it will update those things with the
|
46
|
+
values in the YAML file).
|
47
|
+
|
48
|
+
You'll then be able to do this:
|
49
|
+
|
50
|
+
thing = Thing.find_by_name(:foo)
|
51
|
+
thing.colour ---> 'red'
|
52
|
+
|
53
|
+
Each time seeds.rb is run, Seeder will output a report detailing start and
|
54
|
+
end time, and a log of how the number of things has changed.
|
55
|
+
|
56
|
+
Have a look at the lib/examples folder, for a more detailed guide to how
|
57
|
+
Dibber is used.
|
data/lib/dibber/seeder.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'yaml'
|
3
|
+
|
1
4
|
module Dibber
|
2
5
|
class Seeder
|
3
|
-
attr_accessor :klass, :file, :
|
6
|
+
attr_accessor :klass, :file, :attribute_method, :name_method
|
4
7
|
|
5
8
|
def self.process_log
|
6
9
|
@process_log || start_process_log
|
@@ -13,7 +16,7 @@ module Dibber
|
|
13
16
|
end
|
14
17
|
|
15
18
|
def self.report
|
16
|
-
|
19
|
+
process_log.report
|
17
20
|
end
|
18
21
|
|
19
22
|
def self.monitor(klass)
|
@@ -34,17 +37,20 @@ module Dibber
|
|
34
37
|
end
|
35
38
|
|
36
39
|
|
37
|
-
def initialize(klass, file,
|
40
|
+
def initialize(klass, file, args = {})
|
38
41
|
@klass = klass
|
39
42
|
@file = file
|
40
|
-
|
43
|
+
args = {:attributes_method => args} unless args.kind_of?(Hash)
|
44
|
+
@attribute_method = args[:attributes_method] || 'attributes'
|
45
|
+
@name_method = args[:name_method] || 'name'
|
41
46
|
end
|
42
47
|
|
43
48
|
def build
|
44
49
|
start_log
|
50
|
+
check_objects_exist
|
45
51
|
objects.each do |name, attributes|
|
46
|
-
object = klass.
|
47
|
-
object.send("#{
|
52
|
+
object = klass.send(retrieval_method, name)
|
53
|
+
object.send("#{attribute_method}=", attributes)
|
48
54
|
object.save
|
49
55
|
end
|
50
56
|
end
|
@@ -54,13 +60,21 @@ module Dibber
|
|
54
60
|
end
|
55
61
|
|
56
62
|
def objects
|
57
|
-
self.class.objects_from(file)
|
63
|
+
@objects ||= self.class.objects_from(file)
|
58
64
|
end
|
59
65
|
|
60
66
|
private
|
61
67
|
def self.raise_no_seeds_path_error
|
62
68
|
raise "You must set the path to your seed files via Seeder.seeds_path = 'path/to/seed/files'"
|
63
69
|
end
|
70
|
+
|
71
|
+
def check_objects_exist
|
72
|
+
raise "No objects returned from file: #{self.class.seeds_path}#{file}" unless objects
|
73
|
+
end
|
74
|
+
|
75
|
+
def retrieval_method
|
76
|
+
"find_or_initialize_by_#{name_method}"
|
77
|
+
end
|
64
78
|
|
65
79
|
end
|
66
80
|
end
|
data/lib/dibber/thing.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
class Thing
|
2
|
+
attr_reader :name
|
3
|
+
attr_accessor :attributes, :other_method
|
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 unless self.class.saved.include? self
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.find_or_initialize_by_name(name)
|
16
|
+
existing = members.select{|m| m.name == name.to_s}
|
17
|
+
if existing.empty?
|
18
|
+
new(name)
|
19
|
+
else
|
20
|
+
existing.first
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.find_or_initialize_by_other_method(data)
|
25
|
+
existing = members.select{|m| m.other_method == data.to_s}
|
26
|
+
if existing.empty?
|
27
|
+
thing = new
|
28
|
+
thing.other_method = data.to_s
|
29
|
+
thing
|
30
|
+
else
|
31
|
+
existing.first
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.members
|
36
|
+
@members ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.count
|
40
|
+
members.length
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.saved
|
44
|
+
@saved ||= []
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.clear_all
|
48
|
+
@members = []
|
49
|
+
@saved = []
|
50
|
+
end
|
51
|
+
end
|
data/lib/dibber/version.rb
CHANGED
data/lib/examples/seeds.rb
CHANGED
@@ -23,18 +23,30 @@ AdminUser.create!(
|
|
23
23
|
# Example 3. Seeder grabs the attributes from the YAML and builds a
|
24
24
|
# set of Fee objects with those attributes (or updates them if
|
25
25
|
# they already exist).
|
26
|
-
# Note that the build process
|
26
|
+
# Note that the build process defaults to using a 'name' field to store
|
27
|
+
# the root key.
|
27
28
|
Seeder.new(Fee, 'fees.yml').build
|
28
29
|
|
29
|
-
# Example 4. Seeder
|
30
|
+
# Example 4. Seeder using an alternative name field
|
31
|
+
Seeder.new(Fee, 'fees.yml', :name_field => :title).build
|
32
|
+
|
33
|
+
# Example 5. Seeder working with a name spaced object
|
30
34
|
Seeder.new(Disclaimer::Document, 'disclaimer/documents.yml').build
|
31
35
|
|
32
|
-
# Example
|
36
|
+
# Example 6. Seeder using values in the yaml file to set a single field
|
33
37
|
Seeder.new(Category, 'categories.yml', 'description').build
|
34
38
|
|
39
|
+
# Example 7. Seeder using alternative name and attributes fields
|
40
|
+
Seeder.new(
|
41
|
+
Category,
|
42
|
+
'categories.yml',
|
43
|
+
:name_field => :title,
|
44
|
+
:attributes_field => :description
|
45
|
+
).build
|
46
|
+
|
47
|
+
# You can also access Seeders attached process log, and set up a custom log
|
48
|
+
Seeder.process_log.start('First questionnaire questions', 'Questionnaire.count > 0 ? Questionnaire.first.questions.length : 0')
|
49
|
+
|
35
50
|
# Output a report showing how the numbers of each type of object
|
36
51
|
# have changed through the process. Also has a log of start and end time.
|
37
52
|
puts Seeder.report
|
38
|
-
|
39
|
-
# You can also access Seeders attached process log, and set up a custom log
|
40
|
-
Seeder.process_log.start('First questionnaire questions', 'Questionnaire.count > 0 ? Questionnaire.first.questions.length : 0')
|
@@ -0,0 +1,112 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'../..','lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'dibber'
|
5
|
+
require 'dibber/thing'
|
6
|
+
|
7
|
+
module Dibber
|
8
|
+
|
9
|
+
class SeederTest < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def setup
|
12
|
+
Seeder.seeds_path = File.join(File.dirname(__FILE__),'seeds')
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
Thing.clear_all
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_process_log
|
20
|
+
assert_kind_of(ProcessLog, Seeder.process_log)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_process_log_start
|
24
|
+
@log = Seeder.process_log
|
25
|
+
assert(@log.raw.keys.include?(:time), 'time should be logged')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_report
|
29
|
+
test_process_log_start
|
30
|
+
assert_equal(@log.report, Seeder.report)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_monitor
|
34
|
+
Seeder.monitor(Thing)
|
35
|
+
assert_equal({:command => 'Thing.count', :start => Thing.count}, Seeder.process_log.raw[:things])
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_seeds_path
|
39
|
+
assert_match(/test\/dibber\/seeds\/$/, Seeder.seeds_path)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_objects_from
|
43
|
+
content = YAML.load_file(thing_file_path)
|
44
|
+
assert_equal(content, Seeder.objects_from('things.yml'))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_start_log
|
48
|
+
thing_seeder.start_log
|
49
|
+
assert(Seeder.process_log.raw.keys.include?(:things), 'Things should be logged')
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_objects
|
53
|
+
content = YAML.load_file(thing_file_path)
|
54
|
+
assert_equal(content, thing_seeder.objects)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_build_with_no_objects
|
58
|
+
thing_seeder = Seeder.new(Thing, 'empty.yml')
|
59
|
+
assert_raise RuntimeError do
|
60
|
+
thing_seeder.build
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_build
|
65
|
+
assert_equal(0, Thing.count)
|
66
|
+
thing_seeder.build
|
67
|
+
assert_equal(2, Thing.count)
|
68
|
+
foo = Thing.find_or_initialize_by_name(:foo)
|
69
|
+
bar = Thing.find_or_initialize_by_name(:bar)
|
70
|
+
assert_equal([foo, bar], Thing.saved)
|
71
|
+
assert_equal({'title' => 'one'}, foo.attributes)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_other_method_replacing_attributes
|
75
|
+
thing_seeder('other_method').build
|
76
|
+
foo = Thing.find_or_initialize_by_name(:foo)
|
77
|
+
bar = Thing.find_or_initialize_by_name(:bar)
|
78
|
+
assert_equal([foo, bar], Thing.saved)
|
79
|
+
assert_nil(foo.attributes)
|
80
|
+
assert_equal({'title' => 'one'}, foo.other_method)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_other_method_replacing_attributes_via_args
|
84
|
+
thing_seeder(:attributes_method => 'other_method').build
|
85
|
+
foo = Thing.find_or_initialize_by_name(:foo)
|
86
|
+
bar = Thing.find_or_initialize_by_name(:bar)
|
87
|
+
assert_equal([foo, bar], Thing.saved)
|
88
|
+
assert_nil(foo.attributes)
|
89
|
+
assert_equal({'title' => 'one'}, foo.other_method)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_alternative_name_method
|
93
|
+
thing_seeder(:name_method => 'other_method').build
|
94
|
+
assert_equal(2, Thing.count)
|
95
|
+
foo = Thing.find_or_initialize_by_other_method(:foo)
|
96
|
+
bar = Thing.find_or_initialize_by_other_method(:bar)
|
97
|
+
assert_equal([foo, bar], Thing.saved)
|
98
|
+
assert_equal({'title' => 'one'}, foo.attributes)
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
private
|
103
|
+
def thing_seeder(method = 'attributes')
|
104
|
+
@thing_seeder = Seeder.new(Thing, 'things.yml', method)
|
105
|
+
end
|
106
|
+
|
107
|
+
def thing_file_path
|
108
|
+
File.join(File.dirname(__FILE__),'seeds', 'things.yml')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'../..','lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'dibber/thing'
|
5
|
+
|
6
|
+
module Dibber
|
7
|
+
|
8
|
+
class ThingTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
Thing.clear_all
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_find_or_initialize_by_name
|
15
|
+
@name = 'foo'
|
16
|
+
@thing = Thing.find_or_initialize_by_name(@name)
|
17
|
+
assert_equal(@name, @thing.name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_find_or_initialize_by_name_with_symbol
|
21
|
+
test_find_or_initialize_by_name
|
22
|
+
assert_equal(1, Thing.count)
|
23
|
+
thing = Thing.find_or_initialize_by_name(:foo)
|
24
|
+
assert_equal(1, Thing.count)
|
25
|
+
assert_equal('foo', thing.name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_find_or_initialize_by_name_when_thing_exists
|
29
|
+
test_find_or_initialize_by_name
|
30
|
+
test_find_or_initialize_by_name
|
31
|
+
assert_equal(1, Thing.count)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_count
|
35
|
+
assert_equal(0, Thing.count)
|
36
|
+
Thing.find_or_initialize_by_name(:thing_for_count_test)
|
37
|
+
assert_equal(1, Thing.count)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_attributes
|
41
|
+
stuff = %w{this that}
|
42
|
+
test_find_or_initialize_by_name
|
43
|
+
@thing.attributes = stuff
|
44
|
+
assert_equal(stuff, @thing.attributes)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_other_method
|
48
|
+
stuff = %w{come home mother}
|
49
|
+
test_find_or_initialize_by_name
|
50
|
+
@thing.other_method = stuff
|
51
|
+
assert_equal(stuff, @thing.other_method)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_save_and_saved
|
55
|
+
thing = Thing.find_or_initialize_by_name(:thing_for_save_test)
|
56
|
+
assert !Thing.saved.include?(thing), 'saved things should not include thing'
|
57
|
+
assert thing.save, 'should return true on save'
|
58
|
+
assert Thing.saved.include?(thing), 'saved things should include thing'
|
59
|
+
thing.save
|
60
|
+
assert_equal(1, Thing.saved.select{|t| t == thing}.length)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_clear
|
64
|
+
test_find_or_initialize_by_name
|
65
|
+
@thing.save
|
66
|
+
assert_not_equal(0, Thing.count)
|
67
|
+
assert_not_equal([], Thing.saved)
|
68
|
+
Thing.clear_all
|
69
|
+
assert_equal(0, Thing.count)
|
70
|
+
assert_equal([], Thing.saved)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_find_or_initialize_by_other_method
|
74
|
+
thing = Thing.find_or_initialize_by_other_method(:something)
|
75
|
+
assert_nil(thing.name)
|
76
|
+
assert_equal('something', thing.other_method)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
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.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
12
|
+
date: 2013-01-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: active_support
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
description: Packages up code needed to pull data from YAML files when seeding, and
|
15
31
|
adds a process log.
|
16
32
|
email:
|
@@ -27,12 +43,17 @@ files:
|
|
27
43
|
- lib/examples/seeds.rb
|
28
44
|
- lib/dibber.rb
|
29
45
|
- lib/dibber/version.rb
|
46
|
+
- lib/dibber/thing.rb
|
30
47
|
- lib/dibber/process_log.rb
|
31
48
|
- lib/dibber/seeder.rb
|
32
49
|
- MIT-LICENSE
|
33
50
|
- Rakefile
|
34
51
|
- README.rdoc
|
52
|
+
- test/dibber/seeder_test.rb
|
35
53
|
- test/dibber/process_log_test.rb
|
54
|
+
- test/dibber/seeds/empty.yml
|
55
|
+
- test/dibber/seeds/things.yml
|
56
|
+
- test/dibber/thing_test.rb
|
36
57
|
homepage: https://github.com/reggieb/Dibber
|
37
58
|
licenses: []
|
38
59
|
post_install_message:
|
@@ -58,4 +79,8 @@ signing_key:
|
|
58
79
|
specification_version: 3
|
59
80
|
summary: Tool for seeding database from YAML.
|
60
81
|
test_files:
|
82
|
+
- test/dibber/seeder_test.rb
|
61
83
|
- test/dibber/process_log_test.rb
|
84
|
+
- test/dibber/seeds/empty.yml
|
85
|
+
- test/dibber/seeds/things.yml
|
86
|
+
- test/dibber/thing_test.rb
|