dibber 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|