blueprints 0.6.3 → 0.7.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/README.rdoc +65 -66
- data/Rakefile +4 -0
- data/VERSION +1 -1
- data/bin/blueprintify +80 -0
- data/blueprints.gemspec +21 -5
- data/lib/blueprints.rb +26 -51
- data/lib/blueprints/{plan.rb → blueprint.rb} +4 -4
- data/lib/blueprints/buildable.rb +2 -2
- data/lib/blueprints/configuration.rb +42 -0
- data/lib/blueprints/convertable.rb +30 -0
- data/lib/blueprints/convertable/fixtures.rb +43 -0
- data/lib/blueprints/database_backends/active_record.rb +44 -85
- data/lib/blueprints/errors.rb +3 -3
- data/lib/blueprints/extensions/deprecated.rb +22 -0
- data/lib/blueprints/extensions/rspec.rb +7 -32
- data/lib/blueprints/extensions/test_unit.rb +9 -18
- data/lib/blueprints/file_context.rb +3 -3
- data/lib/blueprints/helper.rb +7 -5
- data/lib/blueprints/namespace.rb +2 -2
- data/lib/blueprints/root_namespace.rb +13 -9
- data/spec/active_record/blueprints_spec.rb +7 -49
- data/spec/active_record/spec_helper.rb +6 -1
- data/spec/no_db/spec_helper.rb +6 -1
- data/spec/test_all.sh +32 -0
- data/spec/unit/configuration_spec.rb +34 -0
- data/spec/unit/spec_helper.rb +17 -0
- data/test/blueprints_test.rb +7 -49
- data/test/test_helper.rb +6 -2
- metadata +51 -12
- data/lib/blueprints/database_backends/abstract.rb +0 -21
- data/lib/blueprints/database_backends/none.rb +0 -18
@@ -1,15 +1,15 @@
|
|
1
1
|
module Blueprints
|
2
2
|
# Class for actual blueprints. Allows building itself by executing block passed against current context.
|
3
|
-
class
|
3
|
+
class Blueprint < Buildable
|
4
4
|
# Initializes blueprint by name and block
|
5
5
|
def initialize(name, &block)
|
6
6
|
super(name)
|
7
7
|
@block = block
|
8
8
|
end
|
9
9
|
|
10
|
-
# Builds
|
10
|
+
# Builds blueprint and adds it to executed blueprint hash. Setups instance variable with same name as blueprint if it is not defined yet.
|
11
11
|
def build_self(build_once = true)
|
12
|
-
if build_once and Namespace.root.
|
12
|
+
if build_once and Namespace.root.executed_blueprints.include?(path)
|
13
13
|
Blueprints.warn("Building with options, but blueprint was already built", @name) if Namespace.root.context.options.present?
|
14
14
|
else
|
15
15
|
surface_errors do
|
@@ -19,7 +19,7 @@ module Blueprints
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
Namespace.root.
|
22
|
+
Namespace.root.executed_blueprints << path
|
23
23
|
@result
|
24
24
|
end
|
25
25
|
|
data/lib/blueprints/buildable.rb
CHANGED
@@ -74,7 +74,7 @@ module Blueprints
|
|
74
74
|
@parents.each do |p|
|
75
75
|
parent = begin
|
76
76
|
namespace[p]
|
77
|
-
rescue
|
77
|
+
rescue BlueprintNotFoundError
|
78
78
|
Namespace.root[p]
|
79
79
|
end
|
80
80
|
|
@@ -90,7 +90,7 @@ module Blueprints
|
|
90
90
|
name = name.to_sym unless name == ''
|
91
91
|
return name, []
|
92
92
|
else
|
93
|
-
raise TypeError, "Pass
|
93
|
+
raise TypeError, "Pass blueprint names as strings or symbols only, cannot define blueprint #{name.inspect}"
|
94
94
|
end
|
95
95
|
end
|
96
96
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Blueprints
|
2
|
+
class Configuration
|
3
|
+
SUPPORTED_ORMS = [nil, :active_record]
|
4
|
+
# Allows passing custom filename pattern in case blueprints are held in place other than spec/blueprint, test/blueprint, blueprint.
|
5
|
+
attr_accessor :filename
|
6
|
+
# Allows passing scenarios that should be prebuilt and available in all tests. Works similarly to fixtures.
|
7
|
+
attr_accessor :prebuild
|
8
|
+
# Allows passing custom root folder to use in case of non rails project. Defaults to RAILS_ROOT or current folder if RAILS_ROOT is not defined.
|
9
|
+
attr_accessor :root
|
10
|
+
# By default blueprints runs each test in it's own transaction. This may sometimes be not desirable so this options allows to turn this off.
|
11
|
+
attr_accessor :transactions
|
12
|
+
# Returns ORM that is used, default is :active_record
|
13
|
+
attr_reader :orm
|
14
|
+
|
15
|
+
# Sets default attributes for all attributes
|
16
|
+
def initialize
|
17
|
+
@filename = [nil, "spec", "test"].map do |dir|
|
18
|
+
["blueprint"].map do |file|
|
19
|
+
path = File.join([dir, file].compact)
|
20
|
+
["#{path}.rb", File.join(path, "*.rb")]
|
21
|
+
end
|
22
|
+
end.flatten
|
23
|
+
@orm = :active_record
|
24
|
+
@prebuild = []
|
25
|
+
@transactions = true
|
26
|
+
@root = if defined?(RAILS_ROOT)
|
27
|
+
RAILS_ROOT
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Allows specifying what ORM should be used. See SUPPORTED_ORMS to check what values it can contain.
|
34
|
+
def orm=(value)
|
35
|
+
if SUPPORTED_ORMS.include?(value)
|
36
|
+
@orm = value
|
37
|
+
else
|
38
|
+
raise ArgumentError, "Unsupported ORM #{value.inspect}. Blueprints supports only #{SUPPORTED_ORMS.collect(&:inspect).join(', ')}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Blueprints
|
2
|
+
module Convertable
|
3
|
+
def persist(str)
|
4
|
+
File.open(@output_file, 'a+') do |f|
|
5
|
+
f.write(str)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def process!
|
10
|
+
persist "#{banner_start}#{convert}#{banner_end}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def banner_start
|
14
|
+
"### blueprints from #{@format}\n\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
def banner_end
|
18
|
+
"\n###\n"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Converter
|
23
|
+
def self.for(format, options = {})
|
24
|
+
require "blueprints/convertable/#{format}"
|
25
|
+
Class.new("Blueprints::#{format.capitalize}Converter".constantize) do |options|
|
26
|
+
include Convertable
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Blueprints
|
2
|
+
class FixturesConverter
|
3
|
+
def initialize(options = {})
|
4
|
+
@format = "fixtures"
|
5
|
+
@source_files = options[:source_files]
|
6
|
+
@output_file = options[:output_file]
|
7
|
+
@blueprints_data = ""
|
8
|
+
|
9
|
+
raise "No source files given" unless @source_files
|
10
|
+
raise "No output file given" unless @output_file
|
11
|
+
end
|
12
|
+
|
13
|
+
def convert
|
14
|
+
@source_files.each do |fixture_file|
|
15
|
+
klass = File.basename(fixture_file, '.yml').singularize.capitalize
|
16
|
+
|
17
|
+
loaded_yaml = YAML.load(File.read(fixture_file))
|
18
|
+
|
19
|
+
@blueprints_data = loaded_yaml.collect do |title,yaml_obj|
|
20
|
+
params = yaml_obj.collect do |k,v|
|
21
|
+
":#{k} => #{parameterize(v)}"
|
22
|
+
end.join(', ')
|
23
|
+
|
24
|
+
"#{klass}.blueprint(:#{title}, {#{params}})\n"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@blueprints_data
|
29
|
+
end
|
30
|
+
|
31
|
+
def parameterize(object)
|
32
|
+
if object =~ /<%=\s+?(.+)\s+%>/
|
33
|
+
'('+$1+')'
|
34
|
+
elsif object.is_a?(String)
|
35
|
+
(%Q(#{object})).inspect
|
36
|
+
elsif object.nil?
|
37
|
+
'nil'
|
38
|
+
else
|
39
|
+
object.to_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,94 +1,53 @@
|
|
1
1
|
module Blueprints
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# Returns all tables without skipped ones.
|
34
|
-
def tables
|
35
|
-
::ActiveRecord::Base.connection.tables - skip_tables
|
36
|
-
end
|
37
|
-
|
38
|
-
# Returns tables that should never be cleared (those that contain migrations information).
|
39
|
-
def skip_tables
|
40
|
-
%w( schema_info schema_migrations )
|
41
|
-
end
|
42
|
-
|
43
|
-
# Extensions for active record class
|
44
|
-
module ActiveRecordExtensions
|
45
|
-
module Class
|
46
|
-
# Two forms of this method can be used. First one is typically used inside blueprint block. Essentially it does
|
47
|
-
# same as <tt>create!</tt>, except it does bypass attr_protected and attr_accessible. It accepts only a hash or attributes,
|
48
|
-
# same as <tt>create!</tt> does.
|
49
|
-
# blueprint :post => :user do
|
50
|
-
# @user.posts.blueprint(:title => 'first post', :text => 'My first post')
|
51
|
-
# end
|
52
|
-
# The second form is used when you want to define new blueprint. It takes first argument as name of blueprint
|
53
|
-
# and second one as hash of attributes. As you cannot use instance variables outside of blueprint block, you need
|
54
|
-
# to prefix them with colon. So the example above could be rewritten like this:
|
55
|
-
# Post.blueprint(:post, :title => 'first post', :text => 'My first post', :user => d(:user))
|
56
|
-
# or like this:
|
57
|
-
# Post.blueprint(:post, :title => 'first post', :text => 'My first post', :user => :@user).depends_on(:user)
|
58
|
-
# or like this:
|
59
|
-
# Post.blueprint({:post => :user}, :title => 'first post', :text => 'My first post', :user => :@user)
|
60
|
-
def blueprint(name_or_attrs, attrs = {})
|
61
|
-
if Blueprints::FileContext.evaluating
|
62
|
-
klass = self
|
63
|
-
blueprint = Blueprints::Plan.new(name_or_attrs) { klass.blueprint attributes }
|
64
|
-
blueprint.depends_on(*attrs.values.select {|attr| attr.is_a?(Blueprints::Buildable::Dependency) }).attributes(attrs)
|
65
|
-
blueprint
|
66
|
-
else
|
67
|
-
if name_or_attrs.is_a?(Array)
|
68
|
-
name_or_attrs.collect { |attrs| blueprint(attrs) }
|
69
|
-
else
|
70
|
-
object = new
|
71
|
-
object.blueprint(name_or_attrs)
|
72
|
-
object
|
73
|
-
end
|
74
|
-
end
|
2
|
+
# Extensions for active record class
|
3
|
+
module ActiveRecordExtensions
|
4
|
+
module ClassMethods
|
5
|
+
# Two forms of this method can be used. First one is typically used inside blueprint block. Essentially it does
|
6
|
+
# same as <tt>create!</tt>, except it does bypass attr_protected and attr_accessible. It accepts only a hash or attributes,
|
7
|
+
# same as <tt>create!</tt> does.
|
8
|
+
# blueprint :post => :user do
|
9
|
+
# @user.posts.blueprint(:title => 'first post', :text => 'My first post')
|
10
|
+
# end
|
11
|
+
# The second form is used when you want to define new blueprint. It takes first argument as name of blueprint
|
12
|
+
# and second one as hash of attributes. As you cannot use instance variables outside of blueprint block, you need
|
13
|
+
# to prefix them with colon. So the example above could be rewritten like this:
|
14
|
+
# Post.blueprint(:post, :title => 'first post', :text => 'My first post', :user => d(:user))
|
15
|
+
# or like this:
|
16
|
+
# Post.blueprint(:post, :title => 'first post', :text => 'My first post', :user => :@user).depends_on(:user)
|
17
|
+
# or like this:
|
18
|
+
# Post.blueprint({:post => :user}, :title => 'first post', :text => 'My first post', :user => :@user)
|
19
|
+
def blueprint(name_or_attrs, attrs = {})
|
20
|
+
if Blueprints::FileContext.evaluating
|
21
|
+
klass = self
|
22
|
+
blueprint = Blueprints::Blueprint.new(name_or_attrs) { klass.blueprint attributes }
|
23
|
+
blueprint.depends_on(*attrs.values.select {|attr| attr.is_a?(Blueprints::Buildable::Dependency) }).attributes(attrs)
|
24
|
+
blueprint
|
25
|
+
else
|
26
|
+
if name_or_attrs.is_a?(Array)
|
27
|
+
name_or_attrs.collect { |attrs| blueprint(attrs) }
|
28
|
+
else
|
29
|
+
object = new
|
30
|
+
object.blueprint(name_or_attrs)
|
31
|
+
object
|
75
32
|
end
|
76
33
|
end
|
34
|
+
end
|
35
|
+
end
|
77
36
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
86
|
-
send(:attributes=, attributes, false)
|
87
|
-
save!
|
88
|
-
end
|
37
|
+
module InstanceMethods
|
38
|
+
# Updates attributes of object and calls save!. Bypasses attr_protected and attr_accessible.
|
39
|
+
def blueprint(attributes)
|
40
|
+
attributes.each do |attr, value|
|
41
|
+
iv_name = value.iv_name if value.is_a?(Blueprints::Buildable::Dependency)
|
42
|
+
iv_name = value if value.is_a? Symbol and value.to_s =~ /^@.+$/
|
43
|
+
attributes[attr] = Blueprints::Namespace.root.context.instance_variable_get(iv_name) if iv_name
|
89
44
|
end
|
45
|
+
send(:attributes=, attributes, false)
|
46
|
+
save!
|
90
47
|
end
|
91
|
-
|
92
48
|
end
|
93
49
|
end
|
94
50
|
end
|
51
|
+
|
52
|
+
::ActiveRecord::Base.send(:include, Blueprints::ActiveRecordExtensions::InstanceMethods)
|
53
|
+
::ActiveRecord::Base.extend(Blueprints::ActiveRecordExtensions::ClassMethods)
|
data/lib/blueprints/errors.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
module Blueprints
|
2
2
|
# Is raised when blueprint or namespace is not found.
|
3
|
-
class
|
3
|
+
class BlueprintNotFoundError < NameError
|
4
4
|
def initialize(*args)
|
5
|
-
@
|
5
|
+
@blueprints = args
|
6
6
|
end
|
7
7
|
|
8
8
|
def to_s
|
9
|
-
"
|
9
|
+
"Blueprint/namespace not found '#{@blueprints.join(',')}'"
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module EnableBlueprints #:nodoc:
|
2
|
+
def enable_blueprints(options = {})
|
3
|
+
STDERR.puts "DEPRECATION WARNING: enable_blueprints is deprecated. Use Blueprints.enable"
|
4
|
+
Blueprints.enable do |config|
|
5
|
+
options.each {|option, value| config.send("#{option}=", value) }
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module ActiveSupport #:nodoc:all
|
11
|
+
class TestCase
|
12
|
+
include EnableBlueprints
|
13
|
+
end
|
14
|
+
end if defined? ActiveSupport::TestCase
|
15
|
+
|
16
|
+
module Spec #:nodoc:all
|
17
|
+
module Runner
|
18
|
+
class Configuration
|
19
|
+
include EnableBlueprints
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end if defined? Spec or $0 =~ /script.spec$/
|
@@ -1,35 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def enable_blueprints(options = {})
|
7
|
-
Blueprints.load(options)
|
8
|
-
|
9
|
-
include(Blueprints::Helper)
|
10
|
-
before do
|
11
|
-
Blueprints.setup(self)
|
12
|
-
end
|
13
|
-
after do
|
14
|
-
Blueprints.teardown
|
15
|
-
end
|
1
|
+
config_class = defined?(RSpec) ? RSpec : Spec::Runner
|
2
|
+
config_class.configure do |config|
|
3
|
+
config.include(Blueprints::Helper)
|
4
|
+
config.before do
|
5
|
+
Blueprints.setup(self)
|
16
6
|
end
|
17
|
-
|
18
|
-
|
19
|
-
if defined?(RSpec)
|
20
|
-
module RSpec #:nodoc:
|
21
|
-
module Core #:nodoc:
|
22
|
-
class Configuration
|
23
|
-
include Blueprints::RspecMixin
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
else
|
28
|
-
module Spec #:nodoc:
|
29
|
-
module Runner #:nodoc:
|
30
|
-
class Configuration
|
31
|
-
include Blueprints::RspecMixin
|
32
|
-
end
|
33
|
-
end
|
7
|
+
config.after do
|
8
|
+
Blueprints.teardown
|
34
9
|
end
|
35
10
|
end
|
@@ -1,21 +1,12 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
# Enables blueprints in test/unit. Is automatically added if <tt>Spec</tt> is not defined at loading time.
|
12
|
-
# You might need to require it manually in certain case (eg. using both rspec and test/unit).
|
13
|
-
# Accepts options hash. For supported options please check Blueprints.load.
|
14
|
-
def self.enable_blueprints(options = {})
|
15
|
-
include Blueprints::Helper
|
16
|
-
Blueprints.load(options)
|
17
|
-
alias_method_chain :run, :blueprints
|
18
|
-
end
|
1
|
+
module ActiveSupport #:nodoc:all
|
2
|
+
class TestCase
|
3
|
+
include Blueprints::Helper
|
4
|
+
# Runs tests with blueprints support
|
5
|
+
def run_with_blueprints(result, &progress_block)
|
6
|
+
Blueprints.setup(self)
|
7
|
+
run_without_blueprints(result, &progress_block)
|
8
|
+
Blueprints.teardown
|
19
9
|
end
|
10
|
+
alias_method_chain :run, :blueprints
|
20
11
|
end
|
21
12
|
end
|
@@ -3,9 +3,9 @@ module Blueprints
|
|
3
3
|
module FileContext
|
4
4
|
mattr_accessor :evaluating
|
5
5
|
|
6
|
-
# Creates a new
|
7
|
-
def self.blueprint(
|
8
|
-
|
6
|
+
# Creates a new blueprint by name and block passed
|
7
|
+
def self.blueprint(name, &block)
|
8
|
+
Blueprint.new(name, &block)
|
9
9
|
end
|
10
10
|
|
11
11
|
# Creates new namespace by name, and evaluates block against it.
|
data/lib/blueprints/helper.rb
CHANGED
@@ -37,17 +37,19 @@ module Blueprints
|
|
37
37
|
#
|
38
38
|
# TODO: add sample usage
|
39
39
|
def demolish(*args)
|
40
|
+
STDERR.puts "DEPRECATION WARNING: demolish is deprecated and will be changed to support per blueprint demolishing in blueprints 0.8.0"
|
40
41
|
options = args.extract_options!
|
41
|
-
|
42
|
+
args = (ActiveRecord::Base.connection.tables - ['schema_migrations']) if args.blank?
|
43
|
+
args.each {|table| ActiveRecord::Base.connection.execute("DELETE FROM #{table}") }
|
42
44
|
|
43
45
|
if options[:undo] == :all
|
44
|
-
Namespace.root.
|
46
|
+
Namespace.root.executed_blueprints.clear
|
45
47
|
else
|
46
48
|
undo = [options[:undo]].flatten.compact.collect {|bp| bp.to_s }
|
47
|
-
unless (not_found = undo - Namespace.root.
|
48
|
-
raise(
|
49
|
+
unless (not_found = undo - Namespace.root.executed_blueprints.to_a).blank?
|
50
|
+
raise(BlueprintNotFoundError, not_found)
|
49
51
|
end
|
50
|
-
Namespace.root.
|
52
|
+
Namespace.root.executed_blueprints -= undo
|
51
53
|
end
|
52
54
|
end
|
53
55
|
end
|