letter_press 0.0.1
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/.gemtest +0 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +18 -0
- data/letter_press.gemspec +29 -0
- data/lib/generators/letter_press/install/install_generator.rb +24 -0
- data/lib/generators/letter_press/install/templates/blueprint.rb +23 -0
- data/lib/generators/letter_press/model/model_generator.rb +29 -0
- data/lib/letter_press.rb +35 -0
- data/lib/letter_press/blueprint.rb +81 -0
- data/lib/letter_press/ghost.rb +27 -0
- data/lib/letter_press/rails.rb +4 -0
- data/lib/letter_press/railtie.rb +14 -0
- data/lib/letter_press/serial_number.rb +9 -0
- data/lib/letter_press/version.rb +3 -0
- data/spec/letter_press/blueprint_spec.rb +181 -0
- data/spec/letter_press/ghost_spec.rb +43 -0
- data/spec/letter_press/rails_spec.rb +208 -0
- data/spec/letter_press/serial_number_spec.rb +21 -0
- data/spec/letter_press_spec.rb +82 -0
- data/spec/minitest_helper.rb +7 -0
- metadata +153 -0
data/.gemtest
ADDED
File without changes
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 "Anders Törnqvist"
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# LetterPress
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'letter_press'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install letter_press
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
Rake::TestTask.new(:spec) do |t|
|
6
|
+
t.libs.push "lib"
|
7
|
+
t.libs.push "spec"
|
8
|
+
t.test_files = FileList['spec/**/*_spec.rb']
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
task :test => :spec
|
13
|
+
task :default => :test
|
14
|
+
|
15
|
+
desc "open console (require 'letter_press')"
|
16
|
+
task :c do
|
17
|
+
system "irb -I lib -r letter_press"
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/letter_press/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Anders Törnqvist"]
|
6
|
+
gem.email = ["anders.tornqvist@gmail.com"]
|
7
|
+
gem.description = %q{A model factory}
|
8
|
+
gem.summary = %q{A model factory. Say no to fixtures.}
|
9
|
+
gem.homepage = "https://github.com/unders/letter_press"
|
10
|
+
|
11
|
+
gem.files = Dir.glob("{bin,lib,spec}/**/*") + %w[.gemtest
|
12
|
+
Gemfile
|
13
|
+
LICENSE
|
14
|
+
README.md
|
15
|
+
Rakefile
|
16
|
+
letter_press.gemspec]
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.name = "letter_press"
|
20
|
+
gem.require_paths = ["lib"]
|
21
|
+
gem.version = LetterPress::VERSION
|
22
|
+
|
23
|
+
gem.add_development_dependency "activerecord", "~> 3.1"
|
24
|
+
gem.add_development_dependency "railties", "~> 3.1"
|
25
|
+
gem.add_development_dependency "sqlite3", "~> 1.3.4"
|
26
|
+
|
27
|
+
gem.add_development_dependency "minitest", ["~> 2.12"]
|
28
|
+
gem.add_development_dependency "minitest-colorize", ["~> 0.0.4"]
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module LetterPress
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
|
6
|
+
class_option :test_framework, :type => :string, :aliases => "-t",
|
7
|
+
:desc => "Test framework to use LetterPress with"
|
8
|
+
|
9
|
+
def blueprints_file
|
10
|
+
if rspec?
|
11
|
+
copy_file "blueprint.rb", "spec/blueprint.rb"
|
12
|
+
else
|
13
|
+
copy_file "blueprint.rb", "test/blueprint.rb"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def rspec?
|
20
|
+
options[:test_framework].to_sym == :rspec
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# endcoding: utf-8
|
2
|
+
module LetterPress
|
3
|
+
# Add your blueprints here.
|
4
|
+
#
|
5
|
+
# e.g.
|
6
|
+
# class User < Blueprint(ProxyMethods)
|
7
|
+
# default do
|
8
|
+
# name { "Anders" }
|
9
|
+
# admin { false }
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# define(:admin) do
|
13
|
+
# admin { true }
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# class Post < Blueprint(ProxyMethods)
|
18
|
+
# default do
|
19
|
+
# title { "Post #{sn}" }
|
20
|
+
# body { "Lorem ipsum...#" }
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module LetterPress
|
2
|
+
module Generators
|
3
|
+
class ModelGenerator < Rails::Generators::NamedBase
|
4
|
+
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
|
5
|
+
|
6
|
+
def create_blueprint
|
7
|
+
file_name = if File.exists?(File.join(Rails.root, 'test', 'blueprint.rb'))
|
8
|
+
"test/blueprint.rb"
|
9
|
+
elsif File.exists?(File.join(Rails.root, 'spec', 'blueprint.rb'))
|
10
|
+
"spec/blueprint.rb"
|
11
|
+
else
|
12
|
+
raise "Cannot find the blueprint file"
|
13
|
+
end
|
14
|
+
gsub_file(file_name, /.end\s*\Z/mx) { |match| "#{code}\n#{match}" }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def code
|
20
|
+
%Q{\n
|
21
|
+
class #{class_name} < Blueprint(ProxyMethods)
|
22
|
+
default do
|
23
|
+
#{attributes.map { |a| "#{a.name} { #{a.default.inspect} }" }.join("\n ")}
|
24
|
+
end
|
25
|
+
end}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/letter_press.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "letter_press/version"
|
3
|
+
require "letter_press/blueprint"
|
4
|
+
|
5
|
+
module LetterPress
|
6
|
+
def self.Blueprint(jayz_module)
|
7
|
+
Class.new(Blueprint) do
|
8
|
+
include jayz_module
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def make(*args)
|
13
|
+
name.split('::').inject(LetterPress) do |klass_level, name|
|
14
|
+
klass_level.const_get(name)
|
15
|
+
end.make(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
module ProxyMethods
|
19
|
+
def new
|
20
|
+
if @object.valid?
|
21
|
+
@object
|
22
|
+
else
|
23
|
+
fail ActiveRecord::RecordInvalid.new(@object)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def new!
|
28
|
+
@object
|
29
|
+
end
|
30
|
+
|
31
|
+
def save
|
32
|
+
@object.tap { |record| record.save! }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'letter_press/serial_number'
|
2
|
+
require 'letter_press/ghost'
|
3
|
+
|
4
|
+
module LetterPress
|
5
|
+
class Blueprint; end
|
6
|
+
|
7
|
+
class << Blueprint
|
8
|
+
def make(*args)
|
9
|
+
new(*args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def default(options={}, &block)
|
13
|
+
if block_given?
|
14
|
+
ghosts[:default] = Ghost.new(serial_number).instance_eval(&block)
|
15
|
+
else
|
16
|
+
hash = options.merge({})
|
17
|
+
default = ghosts[:default]
|
18
|
+
(default.keys - options.keys).each do |key|
|
19
|
+
hash[key] = default.send(key)
|
20
|
+
end
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def define(method, &block)
|
26
|
+
ghosts[method] = Ghost.new(serial_number).instance_eval(&block)
|
27
|
+
self.class.send(:define_method, method) do |options={}|
|
28
|
+
hash = options.merge({})
|
29
|
+
blueprint = ghosts[method]
|
30
|
+
blueprint_keys = blueprint.keys
|
31
|
+
(blueprint_keys - options.keys).each do |key|
|
32
|
+
hash[key] = blueprint.send(key)
|
33
|
+
end
|
34
|
+
|
35
|
+
default = ghosts.fetch(:default, {})
|
36
|
+
(default.keys - blueprint_keys).each do |key|
|
37
|
+
hash[key] = default.send(key)
|
38
|
+
end
|
39
|
+
|
40
|
+
hash
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def ghosts
|
47
|
+
@ghosts ||={}
|
48
|
+
end
|
49
|
+
|
50
|
+
def serial_number
|
51
|
+
@serial_number ||= SerialNumber.new
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class Blueprint
|
56
|
+
def initialize(*args)
|
57
|
+
symbol = args.first.is_a?(Symbol) ? args.first : :default
|
58
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
59
|
+
klass_names = self.class.name.sub('LetterPress::', '').split('::')
|
60
|
+
@object = klass_names.inject(Kernel) do |klass_level, name|
|
61
|
+
klass_level.const_get(name)
|
62
|
+
end.new
|
63
|
+
|
64
|
+
self.class.send(symbol, options).each do |key, value|
|
65
|
+
@object.send("#{key}=", value)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def new
|
70
|
+
@object
|
71
|
+
end
|
72
|
+
|
73
|
+
def method_missing(method, *args, &block)
|
74
|
+
@object.send(method, *args, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
def respond_to_missing?(method, *)
|
78
|
+
@object.respond_to?(method)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module LetterPress
|
2
|
+
class Ghost
|
3
|
+
def initialize(serial_number)
|
4
|
+
@serial_number = serial_number
|
5
|
+
end
|
6
|
+
|
7
|
+
def sn
|
8
|
+
@serial_number.next
|
9
|
+
end
|
10
|
+
|
11
|
+
def keys
|
12
|
+
@keys ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(method, *args, &block)
|
16
|
+
if block_given?
|
17
|
+
keys << method
|
18
|
+
m = Module.new do
|
19
|
+
define_method(method, &block)
|
20
|
+
end
|
21
|
+
extend m
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module LetterPress
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
config.after_initialize do
|
4
|
+
blueprints = [ File.join(Rails.root, 'test', 'blueprint'),
|
5
|
+
File.join(Rails.root, 'spec', 'blueprint')]
|
6
|
+
blueprints.each do |path|
|
7
|
+
if File.exists?("#{path}.rb")
|
8
|
+
load("#{path}.rb")
|
9
|
+
break
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'minitest_helper'
|
3
|
+
|
4
|
+
module LetterPress
|
5
|
+
module Admin
|
6
|
+
class User < Blueprint; end
|
7
|
+
end
|
8
|
+
class User < Blueprint; end
|
9
|
+
class Comment < Blueprint; end
|
10
|
+
end
|
11
|
+
|
12
|
+
class User
|
13
|
+
extend LetterPress
|
14
|
+
attr_accessor :name
|
15
|
+
def self.counter; @counter; end
|
16
|
+
def self.counter=(c); @counter = c; end
|
17
|
+
def initialize; self.class.counter = 0; end
|
18
|
+
def save; self.class.counter += 1; end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Comment
|
22
|
+
extend LetterPress
|
23
|
+
attr_accessor :user
|
24
|
+
attr_accessor :body
|
25
|
+
end
|
26
|
+
|
27
|
+
module Admin
|
28
|
+
class User
|
29
|
+
extend LetterPress
|
30
|
+
attr_accessor :name
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe LetterPress::Blueprint do
|
35
|
+
describe ".make" do
|
36
|
+
it "creates an instance" do
|
37
|
+
LetterPress::User.make.must_be_instance_of(LetterPress::User)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe ".default" do
|
42
|
+
before do
|
43
|
+
LetterPress::User.default do
|
44
|
+
name { "User 1" }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "when called with a block" do
|
49
|
+
it "saves the block" do
|
50
|
+
LetterPress::User.default.must_equal :name => 'User 1'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "when called without a block" do
|
55
|
+
it "returns a hash" do
|
56
|
+
LetterPress::User.default.must_equal :name => 'User 1'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe ".define" do
|
62
|
+
before do
|
63
|
+
LetterPress::Comment.define(:admin) do
|
64
|
+
user { LetterPress::User.make(:name => 'Anders Admin').new }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "when called with a block" do
|
69
|
+
it "creates a class method specified by the symbol name" do
|
70
|
+
LetterPress::Comment.admin[:user].name.must_equal 'Anders Admin'
|
71
|
+
end
|
72
|
+
|
73
|
+
it "saves the block" do
|
74
|
+
LetterPress::Comment.admin[:user].name.must_equal 'Anders Admin'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "when called without a block" do
|
79
|
+
it "returns a hash" do
|
80
|
+
LetterPress::Comment.admin[:user].name.must_equal 'Anders Admin'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "when the default block values is used" do
|
86
|
+
before do
|
87
|
+
LetterPress::Comment.default do
|
88
|
+
user { User.make(:name => 'Anders Default').new }
|
89
|
+
body { 'I am defined in default' }
|
90
|
+
end
|
91
|
+
LetterPress::Comment.define(:spam) do
|
92
|
+
user { User.make(:name => 'Anders Spam').new }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "when .define(:spam) has not defined the method in its block" do
|
97
|
+
it "returns the body defined in the default block" do
|
98
|
+
LetterPress::Comment.spam[:body].must_equal 'I am defined in default'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
describe "when .define(:spam) has defined the method in its block" do
|
102
|
+
it "returns the value from the spam block" do
|
103
|
+
LetterPress::Comment.spam[:user].name.must_equal 'Anders Spam'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "serial number interpolation with sn method" do
|
109
|
+
before do
|
110
|
+
LetterPress::User.default do
|
111
|
+
name { "User #{sn}" }
|
112
|
+
end
|
113
|
+
LetterPress::User.define(:admin) do
|
114
|
+
name { "Admin #{sn}" }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
it "returns the next number for each hash" do
|
119
|
+
LetterPress::User.admin[:name].must_equal "Admin 1"
|
120
|
+
LetterPress::User.default[:name].must_equal "User 2"
|
121
|
+
LetterPress::User.default[:name].must_equal "User 3"
|
122
|
+
LetterPress::User.admin[:name].must_equal "Admin 4"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#new" do
|
127
|
+
before do
|
128
|
+
LetterPress::User.default do
|
129
|
+
name { 'Anders' }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
it "returns the correct object" do
|
133
|
+
LetterPress::User.make.new.must_be_instance_of(User)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "populates the returned object with the defined values" do
|
137
|
+
LetterPress::User.make.new.name.must_equal 'Anders'
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "when a message is sent to the instance" do
|
142
|
+
before do
|
143
|
+
LetterPress::User.default do
|
144
|
+
name { 'Anders' }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
it "delegates that message" do
|
148
|
+
LetterPress::User.make.save.must_equal 1
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "blocks are not executed when defined" do
|
153
|
+
before do
|
154
|
+
LetterPress::User.default do
|
155
|
+
name { 'Anders' }
|
156
|
+
end
|
157
|
+
LetterPress::Comment.default do
|
158
|
+
user { User.make.save }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it "executes the defined block when its method is called" do
|
163
|
+
LetterPress::Comment.default
|
164
|
+
User.counter.must_equal 1
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "can handle classes within a module namespace" do
|
169
|
+
before do
|
170
|
+
LetterPress::Admin::User.default do
|
171
|
+
name { "Anders is admin" }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it "returns the correct object populated with the default values" do
|
176
|
+
user = Admin::User.make.new
|
177
|
+
user.must_be_instance_of(Admin::User)
|
178
|
+
user.name.must_equal "Anders is admin"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'minitest_helper'
|
2
|
+
|
3
|
+
describe LetterPress::Ghost do
|
4
|
+
before do
|
5
|
+
def Object.next; 1; end
|
6
|
+
@ghost = LetterPress::Ghost.new(Object)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#keys" do
|
10
|
+
it "returns a collection of all messages sent to the object" do
|
11
|
+
@ghost.title { 'block' }
|
12
|
+
@ghost.body { 'block' }
|
13
|
+
@ghost.keys.must_equal [:title, :body]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#sn" do
|
18
|
+
it "returns a serial number" do
|
19
|
+
@ghost.sn.must_equal 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "a message with a block is sent to the object" do
|
24
|
+
it "creates a method that returns the content of the block" do
|
25
|
+
@ghost.title { 'I am a block' }
|
26
|
+
@ghost.title.must_equal 'I am a block'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "doesn't execute the code inside the block until the method is called" do
|
30
|
+
def Object.counter; @counter ||= 0; @counter +=1; end
|
31
|
+
@ghost.title { Object.counter }
|
32
|
+
@ghost.title.must_equal 1
|
33
|
+
@ghost.title.must_equal 2
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "a message is sent with a block containing a string with \#{sn}" do
|
38
|
+
it "interporlates the sn number" do
|
39
|
+
@ghost.town { "I am ghost town number-#{sn}" }
|
40
|
+
@ghost.town.must_equal "I am ghost town number-1"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rails/railtie'
|
4
|
+
require 'active_record'
|
5
|
+
require 'letter_press/rails'
|
6
|
+
require 'minitest_helper'
|
7
|
+
|
8
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3",
|
9
|
+
:database => ":memory:")
|
10
|
+
|
11
|
+
ActiveRecord::Schema.define do
|
12
|
+
create_table :posts do |t|
|
13
|
+
t.string :title
|
14
|
+
t.text :body
|
15
|
+
t.integer :author_id
|
16
|
+
end
|
17
|
+
create_table :authors do |t|
|
18
|
+
t.string :name
|
19
|
+
end
|
20
|
+
create_table :author_users do |t|
|
21
|
+
t.string :name
|
22
|
+
end
|
23
|
+
create_table :bars do |t|
|
24
|
+
t.string :name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Post < ActiveRecord::Base
|
29
|
+
belongs_to :author
|
30
|
+
validates_presence_of :title
|
31
|
+
validates_presence_of :author_id
|
32
|
+
validates_uniqueness_of :title
|
33
|
+
end
|
34
|
+
|
35
|
+
class Author < ActiveRecord::Base
|
36
|
+
validates_presence_of :name
|
37
|
+
class User < ActiveRecord::Base
|
38
|
+
validates_presence_of :name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module Foo
|
43
|
+
class Bar < ActiveRecord::Base
|
44
|
+
validates_presence_of :name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# blueprint.rb
|
49
|
+
module LetterPress
|
50
|
+
class Author < Blueprint(ProxyMethods)
|
51
|
+
default do
|
52
|
+
name { "Anders" }
|
53
|
+
end
|
54
|
+
|
55
|
+
class User < LetterPress::Blueprint(ProxyMethods)
|
56
|
+
default do
|
57
|
+
name { "Anders is the user" }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Post < Blueprint(ProxyMethods)
|
63
|
+
default do
|
64
|
+
title { "Post #{sn}" }
|
65
|
+
body { "Lorem ipsum..." }
|
66
|
+
author { Author.make.save }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module Foo
|
71
|
+
class Bar < LetterPress::Blueprint(ProxyMethods)
|
72
|
+
default do
|
73
|
+
name { 'I am Foo::Bar' }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "ProxyMethods" do
|
80
|
+
describe ".make" do
|
81
|
+
it "returns a proxy object" do
|
82
|
+
Post.make.must_be_instance_of(LetterPress::Post)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#new" do
|
87
|
+
describe "a valid object" do
|
88
|
+
before { @post = Post.make.new }
|
89
|
+
it "returns a populated record" do
|
90
|
+
@post.must_be_instance_of(Post)
|
91
|
+
@post.body.must_equal "Lorem ipsum..."
|
92
|
+
end
|
93
|
+
|
94
|
+
it "does not persist the record" do
|
95
|
+
Post.count.must_equal 0
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "an invalid object" do
|
100
|
+
it "raises an exception" do
|
101
|
+
lambda {
|
102
|
+
Post.make(:author => nil).new
|
103
|
+
}.must_raise(ActiveRecord::RecordInvalid)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "#new!" do
|
109
|
+
describe "a valid object" do
|
110
|
+
before { @post2 = Post.make.new! }
|
111
|
+
it "returns a populated record" do
|
112
|
+
@post2.must_be_instance_of(Post)
|
113
|
+
@post2.body.must_equal "Lorem ipsum..."
|
114
|
+
end
|
115
|
+
|
116
|
+
it "does not persist the record" do
|
117
|
+
Post.count.must_equal 0
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "an invalid object" do
|
122
|
+
it "returns a populated object" do
|
123
|
+
Post.make(:author => nil).new!.body.must_equal "Lorem ipsum..."
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#save" do
|
129
|
+
before { @post3 = Post.make.save }
|
130
|
+
|
131
|
+
describe "a valid object" do
|
132
|
+
it "persists and returns a populated record" do
|
133
|
+
@post3.must_be_instance_of(Post)
|
134
|
+
@post3.body.must_equal "Lorem ipsum..."
|
135
|
+
Post.count.must_equal 1
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "an invalid object" do
|
140
|
+
it "raises an exception" do
|
141
|
+
lambda {
|
142
|
+
Post.make(:author => nil).save
|
143
|
+
}.must_raise(ActiveRecord::RecordInvalid)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'makes fields uniq with #{sn}' do
|
149
|
+
before do
|
150
|
+
user = Author.make.save
|
151
|
+
@post_count = Post.count
|
152
|
+
@post1 = Post.make(:author => user).save
|
153
|
+
@post2 = Post.make(:author => user).save
|
154
|
+
@post3 = Post.make(:author => user).save
|
155
|
+
@post4 = Post.make(:author => user).save
|
156
|
+
end
|
157
|
+
|
158
|
+
it "creates object that has uniq fields" do
|
159
|
+
@post1.valid?.must_equal true
|
160
|
+
@post2.valid?.must_equal true
|
161
|
+
@post3.valid?.must_equal true
|
162
|
+
@post4.valid?.must_equal true
|
163
|
+
Post.count.must_equal (@post_count + 4)
|
164
|
+
end
|
165
|
+
|
166
|
+
after do
|
167
|
+
Post.delete_all
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "can handle classes namespaced by other classes" do
|
172
|
+
before do
|
173
|
+
@user = Author::User.make.save
|
174
|
+
end
|
175
|
+
|
176
|
+
it "returns a populated record" do
|
177
|
+
@user.must_be_instance_of(Author::User)
|
178
|
+
@user.name.must_equal "Anders is the user"
|
179
|
+
end
|
180
|
+
|
181
|
+
it "creates a author user record" do
|
182
|
+
Author::User.count.must_equal 1
|
183
|
+
end
|
184
|
+
|
185
|
+
after do
|
186
|
+
Author::User.delete_all
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "handles classes namespace by an module" do
|
191
|
+
before do
|
192
|
+
@bar = Foo::Bar.make.save
|
193
|
+
end
|
194
|
+
|
195
|
+
it "returns a populated record" do
|
196
|
+
@bar.must_be_instance_of(Foo::Bar)
|
197
|
+
@bar.name.must_equal "I am Foo::Bar"
|
198
|
+
end
|
199
|
+
|
200
|
+
it "creates a bar record" do
|
201
|
+
Foo::Bar.count.must_equal 1
|
202
|
+
end
|
203
|
+
|
204
|
+
after do
|
205
|
+
Foo::Bar.delete_all
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'minitest_helper'
|
2
|
+
describe LetterPress::SerialNumber do
|
3
|
+
before do
|
4
|
+
@serial_number = LetterPress::SerialNumber.new
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "#next" do
|
8
|
+
describe "when called the first time" do
|
9
|
+
it "returns 1" do
|
10
|
+
@serial_number.next.must_equal 1
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "when called the second time" do
|
15
|
+
it "returns the consecutive number" do
|
16
|
+
number = @serial_number.next
|
17
|
+
@serial_number.next.must_equal (number + 1)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'minitest_helper'
|
3
|
+
|
4
|
+
module LetterPress
|
5
|
+
class Blog < Blueprint
|
6
|
+
default do
|
7
|
+
writer { Writer.make.save }
|
8
|
+
body { "I am a default post body" }
|
9
|
+
end
|
10
|
+
|
11
|
+
define(:video) do
|
12
|
+
writer { Writer.make(:name => 'Anders defined in Blog.video').save }
|
13
|
+
url { 'http://www.youtube.com/watch?v=g5950v0kTJg' }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Writer < Blueprint
|
18
|
+
default do
|
19
|
+
name { 'Anders Törnqvist' }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Blog
|
25
|
+
extend LetterPress
|
26
|
+
attr_accessor :writer
|
27
|
+
attr_accessor :body
|
28
|
+
attr_accessor :url
|
29
|
+
def save; 'save in post called'; end
|
30
|
+
def save!; self; end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Writer
|
34
|
+
extend LetterPress
|
35
|
+
attr_accessor :name
|
36
|
+
def save; self; end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe LetterPress do
|
40
|
+
describe "when extending a class with the LetterPress module" do
|
41
|
+
it "adds a .make method" do
|
42
|
+
Blog.make.must_be_instance_of(LetterPress::Blog)
|
43
|
+
end
|
44
|
+
|
45
|
+
describe ".make" do
|
46
|
+
it "creates a blueprint proxy object" do
|
47
|
+
Blog.make.must_be_instance_of(LetterPress::Blog)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "blueprint proxy object" do
|
52
|
+
it "delegate all messages" do
|
53
|
+
Blog.make.save.must_equal 'save in post called'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "before it delegates a message" do
|
58
|
+
it "populates the receiver with values from the blueprint" do
|
59
|
+
Blog.make.save!.body.must_equal 'I am a default post body'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe ".make message with a symbol argument" do
|
64
|
+
before { @video = Blog.make(:video).save! }
|
65
|
+
it "populates the receiver with values defined in the video block" do
|
66
|
+
@video.url.must_equal 'http://www.youtube.com/watch?v=g5950v0kTJg'
|
67
|
+
end
|
68
|
+
|
69
|
+
it %q{populates the receiver with values from the default block if not
|
70
|
+
defined in video block} do
|
71
|
+
@video.body.must_equal 'I am a default post body'
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "inside a blueprint block" do
|
75
|
+
it "can create other objects" do
|
76
|
+
@video.writer.name.must_equal 'Anders defined in Blog.video'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: letter_press
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Anders Törnqvist
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.1'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.1'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: railties
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3.1'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3.1'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: sqlite3
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.3.4
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.3.4
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2.12'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2.12'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: minitest-colorize
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.0.4
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.0.4
|
94
|
+
description: A model factory
|
95
|
+
email:
|
96
|
+
- anders.tornqvist@gmail.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- lib/generators/letter_press/install/install_generator.rb
|
102
|
+
- lib/generators/letter_press/install/templates/blueprint.rb
|
103
|
+
- lib/generators/letter_press/model/model_generator.rb
|
104
|
+
- lib/letter_press/blueprint.rb
|
105
|
+
- lib/letter_press/ghost.rb
|
106
|
+
- lib/letter_press/rails.rb
|
107
|
+
- lib/letter_press/railtie.rb
|
108
|
+
- lib/letter_press/serial_number.rb
|
109
|
+
- lib/letter_press/version.rb
|
110
|
+
- lib/letter_press.rb
|
111
|
+
- spec/letter_press/blueprint_spec.rb
|
112
|
+
- spec/letter_press/ghost_spec.rb
|
113
|
+
- spec/letter_press/rails_spec.rb
|
114
|
+
- spec/letter_press/serial_number_spec.rb
|
115
|
+
- spec/letter_press_spec.rb
|
116
|
+
- spec/minitest_helper.rb
|
117
|
+
- .gemtest
|
118
|
+
- Gemfile
|
119
|
+
- LICENSE
|
120
|
+
- README.md
|
121
|
+
- Rakefile
|
122
|
+
- letter_press.gemspec
|
123
|
+
homepage: https://github.com/unders/letter_press
|
124
|
+
licenses: []
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 1.8.21
|
144
|
+
signing_key:
|
145
|
+
specification_version: 3
|
146
|
+
summary: A model factory. Say no to fixtures.
|
147
|
+
test_files:
|
148
|
+
- spec/letter_press/blueprint_spec.rb
|
149
|
+
- spec/letter_press/ghost_spec.rb
|
150
|
+
- spec/letter_press/rails_spec.rb
|
151
|
+
- spec/letter_press/serial_number_spec.rb
|
152
|
+
- spec/letter_press_spec.rb
|
153
|
+
- spec/minitest_helper.rb
|