machinist 1.0.6 → 2.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.
Files changed (45) hide show
  1. data/.gitignore +7 -4
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +47 -0
  4. data/MIT-LICENSE +2 -1
  5. data/README.markdown +182 -204
  6. data/Rakefile +22 -29
  7. data/VERSION +1 -1
  8. data/lib/generators/machinist/install/USAGE +2 -0
  9. data/lib/generators/machinist/install/install_generator.rb +46 -0
  10. data/lib/generators/machinist/install/templates/blueprints.rb +9 -0
  11. data/lib/generators/machinist/install/templates/machinist.rb.erb +7 -0
  12. data/lib/generators/machinist/model/model_generator.rb +13 -0
  13. data/lib/machinist/active_record/blueprint.rb +16 -0
  14. data/lib/machinist/active_record/lathe.rb +24 -0
  15. data/lib/machinist/active_record.rb +8 -93
  16. data/lib/machinist/blueprint.rb +89 -0
  17. data/lib/machinist/exceptions.rb +32 -0
  18. data/lib/machinist/lathe.rb +68 -0
  19. data/lib/machinist/machinable.rb +95 -0
  20. data/lib/machinist/version.rb +3 -0
  21. data/lib/machinist.rb +4 -109
  22. data/machinist.gemspec +20 -65
  23. data/spec/active_record_spec.rb +85 -171
  24. data/spec/blueprint_spec.rb +76 -0
  25. data/spec/exceptions_spec.rb +20 -0
  26. data/spec/inheritance_spec.rb +104 -0
  27. data/spec/machinable_spec.rb +101 -0
  28. data/spec/spec_helper.rb +4 -6
  29. data/spec/support/active_record_environment.rb +65 -0
  30. metadata +125 -37
  31. data/.autotest +0 -7
  32. data/FAQ.markdown +0 -18
  33. data/init.rb +0 -2
  34. data/lib/machinist/blueprints.rb +0 -25
  35. data/lib/machinist/data_mapper.rb +0 -83
  36. data/lib/machinist/object.rb +0 -30
  37. data/lib/machinist/sequel.rb +0 -62
  38. data/lib/sham.rb +0 -77
  39. data/spec/data_mapper_spec.rb +0 -134
  40. data/spec/db/.gitignore +0 -1
  41. data/spec/db/schema.rb +0 -20
  42. data/spec/log/.gitignore +0 -1
  43. data/spec/machinist_spec.rb +0 -190
  44. data/spec/sequel_spec.rb +0 -146
  45. data/spec/sham_spec.rb +0 -95
@@ -0,0 +1,65 @@
1
+ require 'active_record'
2
+ require 'machinist/active_record'
3
+
4
+ ActiveRecord::Base.establish_connection(
5
+ :adapter => "mysql",
6
+ :database => "machinist",
7
+ :username => "root",
8
+ :password => ""
9
+ )
10
+
11
+ ActiveRecord::Schema.define(:version => 0) do
12
+ create_table :users, :force => true do |t|
13
+ t.column :username, :string
14
+ end
15
+
16
+ create_table :posts, :force => true do |t|
17
+ t.column :title, :string
18
+ t.column :author_id, :integer
19
+ t.column :body, :text
20
+ end
21
+
22
+ create_table :comments, :force => true do |t|
23
+ t.column :post_id, :integer
24
+ t.column :body, :text
25
+ end
26
+
27
+ create_table :tags, :force => true do |t|
28
+ t.column :name, :string
29
+ end
30
+
31
+ create_table :posts_tags, :id => false, :force => true do |t|
32
+ t.column :post_id, :integer
33
+ t.column :tag_id, :integer
34
+ end
35
+ end
36
+
37
+ class User < ActiveRecord::Base
38
+ validates_presence_of :username
39
+ validates_uniqueness_of :username
40
+ end
41
+
42
+ class Post < ActiveRecord::Base
43
+ has_many :comments
44
+ belongs_to :author, :class_name => "User"
45
+ has_and_belongs_to_many :tags
46
+ end
47
+
48
+ class Comment < ActiveRecord::Base
49
+ belongs_to :post
50
+ end
51
+
52
+ class Tag < ActiveRecord::Base
53
+ has_and_belongs_to_many :posts
54
+ end
55
+
56
+ module ActiveRecordEnvironment
57
+
58
+ def empty_database!
59
+ [User, Post, Comment].each do |klass|
60
+ klass.delete_all
61
+ klass.clear_blueprints!
62
+ end
63
+ end
64
+
65
+ end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: machinist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ hash: 3
5
+ prerelease:
6
+ segments:
7
+ - 2
8
+ - 0
9
+ version: "2.0"
5
10
  platform: ruby
6
11
  authors:
7
12
  - Pete Yandell
@@ -9,86 +14,169 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2009-11-29 00:00:00 +11:00
13
- default_executable:
17
+ date: 2012-01-13 00:00:00 Z
14
18
  dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: activerecord
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: mysql
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ hash: 3
42
+ segments:
43
+ - 0
44
+ version: "0"
45
+ type: :development
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 3
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ type: :development
60
+ version_requirements: *id003
61
+ - !ruby/object:Gem::Dependency
62
+ name: rcov
63
+ prerelease: false
64
+ requirement: &id004 !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ type: :development
74
+ version_requirements: *id004
15
75
  - !ruby/object:Gem::Dependency
16
76
  name: rspec
77
+ prerelease: false
78
+ requirement: &id005 !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ hash: 3
84
+ segments:
85
+ - 0
86
+ version: "0"
17
87
  type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
88
+ version_requirements: *id005
89
+ - !ruby/object:Gem::Dependency
90
+ name: rdoc
91
+ prerelease: false
92
+ requirement: &id006 !ruby/object:Gem::Requirement
93
+ none: false
20
94
  requirements:
21
95
  - - ">="
22
96
  - !ruby/object:Gem::Version
23
- version: 1.2.8
24
- version:
97
+ hash: 3
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ type: :development
102
+ version_requirements: *id006
25
103
  description:
26
- email: pete@notahat.com
104
+ email:
105
+ - pete@notahat.com
27
106
  executables: []
28
107
 
29
108
  extensions: []
30
109
 
31
- extra_rdoc_files:
32
- - README.markdown
110
+ extra_rdoc_files: []
111
+
33
112
  files:
34
- - .autotest
35
113
  - .gitignore
36
- - FAQ.markdown
114
+ - Gemfile
115
+ - Gemfile.lock
37
116
  - MIT-LICENSE
38
117
  - README.markdown
39
118
  - Rakefile
40
119
  - VERSION
41
- - init.rb
120
+ - lib/generators/machinist/install/USAGE
121
+ - lib/generators/machinist/install/install_generator.rb
122
+ - lib/generators/machinist/install/templates/blueprints.rb
123
+ - lib/generators/machinist/install/templates/machinist.rb.erb
124
+ - lib/generators/machinist/model/model_generator.rb
42
125
  - lib/machinist.rb
43
126
  - lib/machinist/active_record.rb
44
- - lib/machinist/blueprints.rb
45
- - lib/machinist/data_mapper.rb
46
- - lib/machinist/object.rb
47
- - lib/machinist/sequel.rb
48
- - lib/sham.rb
127
+ - lib/machinist/active_record/blueprint.rb
128
+ - lib/machinist/active_record/lathe.rb
129
+ - lib/machinist/blueprint.rb
130
+ - lib/machinist/exceptions.rb
131
+ - lib/machinist/lathe.rb
132
+ - lib/machinist/machinable.rb
133
+ - lib/machinist/version.rb
49
134
  - machinist.gemspec
50
135
  - spec/active_record_spec.rb
51
- - spec/data_mapper_spec.rb
52
- - spec/db/.gitignore
53
- - spec/db/schema.rb
54
- - spec/log/.gitignore
55
- - spec/machinist_spec.rb
56
- - spec/sequel_spec.rb
57
- - spec/sham_spec.rb
136
+ - spec/blueprint_spec.rb
137
+ - spec/exceptions_spec.rb
138
+ - spec/inheritance_spec.rb
139
+ - spec/machinable_spec.rb
58
140
  - spec/spec_helper.rb
59
- has_rdoc: true
141
+ - spec/support/active_record_environment.rb
60
142
  homepage: http://github.com/notahat/machinist
61
143
  licenses: []
62
144
 
63
145
  post_install_message:
64
- rdoc_options:
65
- - --charset=UTF-8
146
+ rdoc_options: []
147
+
66
148
  require_paths:
67
149
  - lib
68
150
  required_ruby_version: !ruby/object:Gem::Requirement
151
+ none: false
69
152
  requirements:
70
153
  - - ">="
71
154
  - !ruby/object:Gem::Version
155
+ hash: 3
156
+ segments:
157
+ - 0
72
158
  version: "0"
73
- version:
74
159
  required_rubygems_version: !ruby/object:Gem::Requirement
160
+ none: false
75
161
  requirements:
76
162
  - - ">="
77
163
  - !ruby/object:Gem::Version
164
+ hash: 3
165
+ segments:
166
+ - 0
78
167
  version: "0"
79
- version:
80
168
  requirements: []
81
169
 
82
- rubyforge_project:
83
- rubygems_version: 1.3.5
170
+ rubyforge_project: machinist
171
+ rubygems_version: 1.8.10
84
172
  signing_key:
85
173
  specification_version: 3
86
174
  summary: Fixtures aren't fun. Machinist is.
87
175
  test_files:
88
176
  - spec/active_record_spec.rb
89
- - spec/data_mapper_spec.rb
90
- - spec/db/schema.rb
91
- - spec/machinist_spec.rb
92
- - spec/sequel_spec.rb
93
- - spec/sham_spec.rb
177
+ - spec/blueprint_spec.rb
178
+ - spec/exceptions_spec.rb
179
+ - spec/inheritance_spec.rb
180
+ - spec/machinable_spec.rb
94
181
  - spec/spec_helper.rb
182
+ - spec/support/active_record_environment.rb
data/.autotest DELETED
@@ -1,7 +0,0 @@
1
- Autotest.add_hook :initialize do |at|
2
- at.clear_mappings
3
-
4
- at.add_mapping(%r%^spec/(.*)_spec.rb$%) {|filename, _| filename }
5
- at.add_mapping(%r%^lib/(.*).rb$%) {|_, match| "spec/#{match[1]}_spec.rb" }
6
- at.add_mapping(%r%^spec/spec_helper.rb$%) { at.files_matching(%r%^spec/(.*)_spec.rb$%) }
7
- end
data/FAQ.markdown DELETED
@@ -1,18 +0,0 @@
1
- Machinist FAQ
2
- =============
3
-
4
- ### My blueprint is giving me really weird errors. Any ideas?
5
-
6
- If your object has an attribute that happens to correspond to a Ruby standard function, it won't work properly in a blueprint.
7
-
8
- For example:
9
-
10
- OpeningHours.blueprint do
11
- open { Time.now }
12
- end
13
-
14
- This will result in Machinist attempting to run ruby's open command. To work around this use self.open instead.
15
-
16
- OpeningHours.blueprint do
17
- self.open { Time.now }
18
- end
data/init.rb DELETED
@@ -1,2 +0,0 @@
1
- require 'machinist' if RAILS_ENV == 'test'
2
-
@@ -1,25 +0,0 @@
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
@@ -1,83 +0,0 @@
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)
@@ -1,30 +0,0 @@
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
@@ -1,62 +0,0 @@
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 DELETED
@@ -1,77 +0,0 @@
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
- method_missing(:name, *args, &block)
9
- end
10
-
11
- def self.method_missing(symbol, *args, &block)
12
- if block_given?
13
- @@shams[symbol] = Sham.new(symbol, args.pop || {}, &block)
14
- else
15
- sham = @@shams[symbol]
16
- raise "No sham defined for #{symbol}" if sham.nil?
17
- sham.fetch_value
18
- end
19
- end
20
-
21
- def self.clear
22
- @@shams = {}
23
- end
24
-
25
- def self.reset(scope = :before_all)
26
- @@shams.values.each { |sham| sham.reset(scope) }
27
- end
28
-
29
- def self.define(&block)
30
- Sham.instance_eval(&block)
31
- end
32
-
33
- def initialize(name, options = {}, &block)
34
- @name = name
35
- @generator = block
36
- @offset = 0
37
- @unique = options.has_key?(:unique) ? options[:unique] : true
38
- generate_values(12)
39
- end
40
-
41
- def reset(scope)
42
- if scope == :before_all
43
- @offset, @before_offset = 0, nil
44
- elsif @before_offset
45
- @offset = @before_offset
46
- else
47
- @before_offset = @offset
48
- end
49
- end
50
-
51
- def fetch_value
52
- # Generate more values if we need them.
53
- if @offset >= @values.length
54
- generate_values(2 * @values.length)
55
- raise "Can't generate more unique values for Sham.#{@name}" if @offset >= @values.length
56
- end
57
- result = @values[@offset]
58
- @offset += 1
59
- result
60
- end
61
-
62
- private
63
-
64
- def generate_values(count)
65
- @values = seeded { (1..count).map(&@generator) }
66
- @values.uniq! if @unique
67
- end
68
-
69
- def seeded
70
- begin
71
- srand(1)
72
- yield
73
- ensure
74
- srand
75
- end
76
- end
77
- end