JamieFlournoy-machinist 1.0.6

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.
@@ -0,0 +1,99 @@
1
+ require 'machinist'
2
+ require 'machinist/blueprints'
3
+ require 'active_record'
4
+
5
+ module Machinist
6
+
7
+ class ActiveRecordAdapter
8
+
9
+ def self.has_association?(object, attribute)
10
+ object.class.reflect_on_association(attribute)
11
+ end
12
+
13
+ def self.class_for_association(object, attribute)
14
+ association = object.class.reflect_on_association(attribute)
15
+ association && association.klass
16
+ end
17
+
18
+ # This method takes care of converting any associated objects,
19
+ # in the hash returned by Lathe#assigned_attributes, into their
20
+ # object ids.
21
+ #
22
+ # For example, let's say we have blueprints like this:
23
+ #
24
+ # Post.blueprint { }
25
+ # Comment.blueprint { post }
26
+ #
27
+ # Lathe#assigned_attributes will return { :post => ... }, but
28
+ # we want to pass { :post_id => 1 } to a controller.
29
+ #
30
+ # This method takes care of cleaning this up.
31
+ def self.assigned_attributes_without_associations(lathe)
32
+ attributes = {}
33
+ lathe.assigned_attributes.each_pair do |attribute, value|
34
+ association = lathe.object.class.reflect_on_association(attribute)
35
+ if association && association.macro == :belongs_to && !value.nil?
36
+ attributes[association.primary_key_name.to_sym] = value.id
37
+ else
38
+ attributes[attribute] = value
39
+ end
40
+ end
41
+ attributes
42
+ end
43
+
44
+ end
45
+
46
+ module ActiveRecordExtensions
47
+ def self.included(base)
48
+ base.extend(ClassMethods)
49
+ end
50
+
51
+ module ClassMethods
52
+ def make(*args, &block)
53
+ lathe = Lathe.run(Machinist::ActiveRecordAdapter, self.new, *args)
54
+ unless Machinist.nerfed?
55
+ lathe.object.save!
56
+ lathe.object.reload
57
+ end
58
+ lathe.object(&block)
59
+ end
60
+
61
+ def make_unsaved(*args)
62
+ object = Machinist.with_save_nerfed { make(*args) }
63
+ yield object if block_given?
64
+ object
65
+ end
66
+
67
+ def plan(*args)
68
+ lathe = Lathe.run(Machinist::ActiveRecordAdapter, self.new, *args)
69
+ Machinist::ActiveRecordAdapter.assigned_attributes_without_associations(lathe)
70
+ end
71
+ end
72
+ end
73
+
74
+ module ActiveRecordHasManyExtensions
75
+ def make(*args, &block)
76
+ lathe = Lathe.run(Machinist::ActiveRecordAdapter, self.build, *args)
77
+ unless Machinist.nerfed?
78
+ lathe.object.save!
79
+ lathe.object.reload
80
+ end
81
+ lathe.object(&block)
82
+ end
83
+
84
+ def plan(*args)
85
+ lathe = Lathe.run(Machinist::ActiveRecordAdapter, self.build, *args)
86
+ Machinist::ActiveRecordAdapter.assigned_attributes_without_associations(lathe)
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ class ActiveRecord::Base
93
+ include Machinist::Blueprints
94
+ include Machinist::ActiveRecordExtensions
95
+ end
96
+
97
+ class ActiveRecord::Associations::HasManyAssociation
98
+ include Machinist::ActiveRecordHasManyExtensions
99
+ end
@@ -0,0 +1,25 @@
1
+ module Machinist
2
+ # Include this in a class to allow defining blueprints for that class.
3
+ module Blueprints
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def blueprint(name = :master, &blueprint)
10
+ @blueprints ||= {}
11
+ @blueprints[name] = blueprint if block_given?
12
+ @blueprints[name]
13
+ end
14
+
15
+ def named_blueprints
16
+ @blueprints.reject{|name,_| name == :master }.keys
17
+ end
18
+
19
+ def clear_blueprints!
20
+ @blueprints = {}
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,83 @@
1
+ require 'machinist'
2
+ require 'machinist/blueprints'
3
+ require 'dm-core'
4
+
5
+ module Machinist
6
+
7
+ class DataMapperAdapter
8
+ def self.has_association?(object, attribute)
9
+ object.class.relationships.has_key?(attribute)
10
+ end
11
+
12
+ def self.class_for_association(object, attribute)
13
+ association = object.class.relationships[attribute]
14
+ association && association.parent_model
15
+ end
16
+
17
+ def self.association_is_many_to_one?(association)
18
+ if defined?(DataMapper::Associations::ManyToOne::Relationship)
19
+ # We're using the next branch of DM
20
+ association.class == DataMapper::Associations::ManyToOne::Relationship
21
+ else
22
+ # We're using the 0.9 or less branch.
23
+ association.options[:max].nil?
24
+ end
25
+ end
26
+
27
+ # This method takes care of converting any associated objects,
28
+ # in the hash returned by Lathe#assigned_attributes, into their
29
+ # object ids.
30
+ #
31
+ # For example, let's say we have blueprints like this:
32
+ #
33
+ # Post.blueprint { }
34
+ # Comment.blueprint { post }
35
+ #
36
+ # Lathe#assigned_attributes will return { :post => ... }, but
37
+ # we want to pass { :post_id => 1 } to a controller.
38
+ #
39
+ # This method takes care of cleaning this up.
40
+ def self.assigned_attributes_without_associations(lathe)
41
+ attributes = {}
42
+ lathe.assigned_attributes.each_pair do |attribute, value|
43
+ association = lathe.object.class.relationships[attribute]
44
+ if association && association_is_many_to_one?(association)
45
+ # DataMapper child_key can have more than one property, but I'm not
46
+ # sure in what circumstances this would be the case. I'm assuming
47
+ # here that there's only one property.
48
+ key = association.child_key.map(&:field).first.to_sym
49
+ attributes[key] = value.id
50
+ else
51
+ attributes[attribute] = value
52
+ end
53
+ end
54
+ attributes
55
+ end
56
+ end
57
+
58
+ module DataMapperExtensions
59
+ def make(*args, &block)
60
+ lathe = Lathe.run(Machinist::DataMapperAdapter, self.new, *args)
61
+ unless Machinist.nerfed?
62
+ lathe.object.save || raise("Save failed")
63
+ lathe.object.reload
64
+ end
65
+ lathe.object(&block)
66
+ end
67
+
68
+ def make_unsaved(*args)
69
+ object = Machinist.with_save_nerfed { make(*args) }
70
+ yield object if block_given?
71
+ object
72
+ end
73
+
74
+ def plan(*args)
75
+ lathe = Lathe.run(Machinist::DataMapperAdapter, self.new, *args)
76
+ Machinist::DataMapperAdapter.assigned_attributes_without_associations(lathe)
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ DataMapper::Model.append_extensions(Machinist::Blueprints::ClassMethods)
83
+ DataMapper::Model.append_extensions(Machinist::DataMapperExtensions)
@@ -0,0 +1,30 @@
1
+ require 'machinist'
2
+ require 'machinist/blueprints'
3
+
4
+ module Machinist
5
+
6
+ module ObjectExtensions
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ def make(*args, &block)
13
+ lathe = Lathe.run(Machinist::ObjectAdapter, self.new, *args)
14
+ lathe.object(&block)
15
+ end
16
+ end
17
+ end
18
+
19
+ class ObjectAdapter
20
+ def self.has_association?(object, attribute)
21
+ false
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ class Object
28
+ include Machinist::Blueprints
29
+ include Machinist::ObjectExtensions
30
+ end
@@ -0,0 +1,62 @@
1
+ require 'machinist'
2
+ require 'machinist/blueprints'
3
+ require 'sequel'
4
+
5
+ module Machinist
6
+ class SequelAdapter
7
+ def self.has_association?(object, attribute)
8
+ object.class.associations.include?(attribute)
9
+ end
10
+
11
+ def self.class_for_association(object, attribute)
12
+ object.class.association_reflection(attribute).associated_class
13
+ end
14
+
15
+ def self.assigned_attributes_without_associations(lathe)
16
+ attributes = {}
17
+ lathe.assigned_attributes.each_pair do |attribute, value|
18
+ association = lathe.object.class.association_reflection(attribute)
19
+ if association && association[:type] == :many_to_one
20
+ key = association[:key] || association.default_key
21
+ attributes[key] = value.send(association.primary_key)
22
+ else
23
+ attributes[attribute] = value
24
+ end
25
+ end
26
+ attributes
27
+ end
28
+ end
29
+
30
+ module SequelExtensions
31
+ def self.included(base)
32
+ base.extend(ClassMethods)
33
+ end
34
+
35
+ module ClassMethods
36
+ def make(*args, &block)
37
+ lathe = Lathe.run(Machinist::SequelAdapter, self.new, *args)
38
+ unless Machinist.nerfed?
39
+ lathe.object.save
40
+ lathe.object.refresh
41
+ end
42
+ lathe.object(&block)
43
+ end
44
+
45
+ def make_unsaved(*args)
46
+ returning(Machinist.with_save_nerfed { make(*args) }) do |object|
47
+ yield object if block_given?
48
+ end
49
+ end
50
+
51
+ def plan(*args)
52
+ lathe = Lathe.run(Machinist::SequelAdapter, self.new, *args)
53
+ Machinist::SequelAdapter.assigned_attributes_without_associations(lathe)
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ class Sequel::Model
60
+ include Machinist::Blueprints
61
+ include Machinist::SequelExtensions
62
+ end
data/lib/sham.rb ADDED
@@ -0,0 +1,81 @@
1
+ class Sham
2
+ @@shams = {}
3
+
4
+ # Over-ride module's built-in name method, so we can re-use it for
5
+ # generating names. This is a bit of a no-no, but we get away with
6
+ # it in this context.
7
+ def self.name(*args, &block)
8
+ if args.empty? && !block_given? && @@shams[:name].nil? # workaround for ZenTest initializer
9
+ super
10
+ else
11
+ method_missing(:name, *args, &block)
12
+ end
13
+ end
14
+
15
+ def self.method_missing(symbol, *args, &block)
16
+ if block_given?
17
+ @@shams[symbol] = Sham.new(symbol, args.pop || {}, &block)
18
+ else
19
+ sham = @@shams[symbol]
20
+ raise "No sham defined for #{symbol}" if sham.nil?
21
+ sham.fetch_value
22
+ end
23
+ end
24
+
25
+ def self.clear
26
+ @@shams = {}
27
+ end
28
+
29
+ def self.reset(scope = :before_all)
30
+ @@shams.values.each { |sham| sham.reset(scope) }
31
+ end
32
+
33
+ def self.define(&block)
34
+ Sham.instance_eval(&block)
35
+ end
36
+
37
+ def initialize(name, options = {}, &block)
38
+ @name = name
39
+ @generator = block
40
+ @offset = 0
41
+ @unique = options.has_key?(:unique) ? options[:unique] : true
42
+ generate_values(12)
43
+ end
44
+
45
+ def reset(scope)
46
+ if scope == :before_all
47
+ @offset, @before_offset = 0, nil
48
+ elsif @before_offset
49
+ @offset = @before_offset
50
+ else
51
+ @before_offset = @offset
52
+ end
53
+ end
54
+
55
+ def fetch_value
56
+ # Generate more values if we need them.
57
+ if @offset >= @values.length
58
+ generate_values(2 * @values.length)
59
+ raise "Can't generate more unique values for Sham.#{@name}" if @offset >= @values.length
60
+ end
61
+ result = @values[@offset]
62
+ @offset += 1
63
+ result
64
+ end
65
+
66
+ private
67
+
68
+ def generate_values(count)
69
+ @values = seeded { (1..count).map(&@generator) }
70
+ @values.uniq! if @unique
71
+ end
72
+
73
+ def seeded
74
+ begin
75
+ srand(1)
76
+ yield
77
+ ensure
78
+ srand
79
+ end
80
+ end
81
+ end
data/machinist.gemspec ADDED
@@ -0,0 +1,90 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{machinist}
8
+ s.version = "1.0.6"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Pete Yandell"]
12
+ s.date = %q{2010-03-23}
13
+ s.email = %q{pete@notahat.com}
14
+ s.extra_rdoc_files = [
15
+ "README.markdown"
16
+ ]
17
+ s.files = [
18
+ ".autotest",
19
+ ".gitignore",
20
+ "FAQ.markdown",
21
+ "MIT-LICENSE",
22
+ "README.markdown",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "init.rb",
26
+ "lib/machinist.rb",
27
+ "lib/machinist/active_record.rb",
28
+ "lib/machinist/blueprints.rb",
29
+ "lib/machinist/data_mapper.rb",
30
+ "lib/machinist/object.rb",
31
+ "lib/machinist/sequel.rb",
32
+ "lib/sham.rb",
33
+ "machinist.gemspec",
34
+ "spec/active_record_spec.rb",
35
+ "spec/data_mapper_spec.rb",
36
+ "spec/db/.gitignore",
37
+ "spec/db/schema.rb",
38
+ "spec/log/.gitignore",
39
+ "spec/machinist_spec.rb",
40
+ "spec/sequel_spec.rb",
41
+ "spec/sham_spec.rb",
42
+ "spec/spec_helper.rb"
43
+ ]
44
+ s.homepage = %q{http://github.com/notahat/machinist}
45
+ s.rdoc_options = ["--charset=UTF-8"]
46
+ s.require_paths = ["lib"]
47
+ s.rubygems_version = %q{1.3.6}
48
+ s.summary = %q{Fixtures aren't fun. Machinist is.}
49
+ s.test_files = [
50
+ "spec/active_record_spec.rb",
51
+ "spec/data_mapper_spec.rb",
52
+ "spec/db/schema.rb",
53
+ "spec/machinist_spec.rb",
54
+ "spec/sequel_spec.rb",
55
+ "spec/sham_spec.rb",
56
+ "spec/spec_helper.rb"
57
+ ]
58
+
59
+ if s.respond_to? :specification_version then
60
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
61
+ s.specification_version = 3
62
+
63
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
64
+ s.add_development_dependency(%q<rspec>, [">= 1.2.8"])
65
+ s.add_development_dependency(%q<activerecord>, [">= 0"])
66
+ s.add_development_dependency(%q<sequel>, [">= 0"])
67
+ s.add_development_dependency(%q<dm-core>, [">= 0"])
68
+ s.add_development_dependency(%q<dm-validations>, [">= 0"])
69
+ s.add_development_dependency(%q<data_objects>, [">= 0"])
70
+ s.add_development_dependency(%q<do_sqlite3>, [">= 0"])
71
+ else
72
+ s.add_dependency(%q<rspec>, [">= 1.2.8"])
73
+ s.add_dependency(%q<activerecord>, [">= 0"])
74
+ s.add_dependency(%q<sequel>, [">= 0"])
75
+ s.add_dependency(%q<dm-core>, [">= 0"])
76
+ s.add_dependency(%q<dm-validations>, [">= 0"])
77
+ s.add_dependency(%q<data_objects>, [">= 0"])
78
+ s.add_dependency(%q<do_sqlite3>, [">= 0"])
79
+ end
80
+ else
81
+ s.add_dependency(%q<rspec>, [">= 1.2.8"])
82
+ s.add_dependency(%q<activerecord>, [">= 0"])
83
+ s.add_dependency(%q<sequel>, [">= 0"])
84
+ s.add_dependency(%q<dm-core>, [">= 0"])
85
+ s.add_dependency(%q<dm-validations>, [">= 0"])
86
+ s.add_dependency(%q<data_objects>, [">= 0"])
87
+ s.add_dependency(%q<do_sqlite3>, [">= 0"])
88
+ end
89
+ end
90
+