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.
@@ -1,13 +1,59 @@
1
1
  = Blueprints
2
2
 
3
- Another replacement for factories and fixtures that focuses on being DRY and making developers type as little as possible.
3
+ Awesome replacement for factories and fixtures that focuses on being DRY and making developers type as little as possible.
4
+
5
+ == Setup
6
+
7
+ The easiest way to install this gem for Ruby on Rails is just add this line to config/environment.rb (or config/environments/test.rb):
8
+
9
+ config.gem 'blueprints'
10
+
11
+ If you're not using rails, then you can install it through command line
12
+
13
+ sudo gem install blueprints
14
+
15
+ Lastly you could use it as plugin:
16
+
17
+ ruby script/plugin install git://github.com/sinsiliux/blueprints.git
18
+
19
+ Blueprints is activated by calling Blueprints.enable at the bottom of your spec_helper/test_helper. If you're using RSpec
20
+ make sure you call Blueprints.enable after requiring RSpec, otherwise it will lead to strange behaviour. This method accepts
21
+ block and yields Blueprints::Configuration object.
22
+
23
+ These options can be set on blueprint configuration object:
24
+ * root - custom framework root if automatic detection fails for some reason (eg. not rails/merb project)
25
+ * filename - custom patterns of files that contain your blueprints (in case one of automatic ones doesn't fit your needs)
26
+ * prebuild - list of blueprints that should be preloaded (available in all tests, never reloaded so they're much faster)
27
+ * orm - allows to set ORM (currently can be :active_record or nil). Defaults to :active_record.
28
+ * transactions - set this to false if you don't want to use transactions. This will severely slow the tests but sometimes transactions can't be used.
29
+
30
+ Sample usage:
31
+
32
+ Blueprints.enable do |config|
33
+ config.filename = 'my_blueprints.rb'
34
+ config.prebuild = :preloaded_blueprint
35
+ end
36
+
37
+ == Blueprints file
38
+
39
+ Blueprints file is the file that contains all definitions of blueprints. This can either be single file or whole folder
40
+ if you have many blueprints.
41
+
42
+ By default blueprints are searched in these files in this particular order in application root (which is either RAILS_ROOT if it's defined or current folder by default):
43
+ * blueprint.rb
44
+ * blueprint/*.rb
45
+ * spec/blueprint.rb
46
+ * spec/blueprint/*.rb
47
+ * test/blueprint.rb
48
+ * test/blueprint/*.rb
49
+ You can set root option to override application root and filename option to pass custom filename pattern.
4
50
 
5
51
  == Usage
6
52
 
7
- Blueprints look like this:
53
+ Definitions of blueprints look like this:
8
54
 
9
55
  blueprint :apple do
10
- Fruit.create! :species => 'apple'
56
+ Fruit.blueprint :species => 'apple'
11
57
  end
12
58
 
13
59
  blueprint :orange do
@@ -15,14 +61,13 @@ Blueprints look like this:
15
61
  end
16
62
 
17
63
  blueprint :fruitbowl => [:apple, :orange] do
18
- FruitBowl.create! :fruit => [@apple,@orange]
64
+ @fruits = [@apple,@orange]
65
+ FruitBowl.blueprint :fruits => @fruits
19
66
  end
20
67
 
21
- blueprint :kitchen => :fruitbowl do
22
- Kitchen.create! :fruitbowl => @fruitbowl
23
- end
68
+ Kitchen.blueprint :kitchen, :fruitbowl => d(:fruitbowl)
24
69
 
25
- ...and you use them in specs like:
70
+ ...and you use them in specs/tests like this:
26
71
 
27
72
  describe Fruit, "apple" do
28
73
  before do
@@ -40,7 +85,8 @@ Blueprints look like this:
40
85
  end
41
86
 
42
87
  it "should have 2 fruits" do
43
- @fruitbowl.should have(2).fruit
88
+ @fruits.should == [@apple, @orange]
89
+ @fruitbowl.should have(2).fruits
44
90
  end
45
91
  end
46
92
 
@@ -77,80 +123,33 @@ And if you also need it to depend on other blueprints:
77
123
 
78
124
  SomeModel.blueprint(:something, :associated_column => :@some_iv).depends_on(:some_blueprint)
79
125
 
80
- ...or if name of associated blueprint and instance variable are same...
126
+ ...or if name of blueprint that this one depends on and instance variable association uses are the same...
81
127
 
82
128
  SomeModel.blueprint(:something, :associated_column => d(:some_blueprint)) # I prefer this one
83
129
 
84
- === Blueprints file
85
-
86
- Blueprints searches for blueprints files in this particular order in Rails (Merb) root:
87
- * blueprint.rb
88
- * blueprint/*.rb
89
- * spec/blueprint.rb
90
- * spec/blueprint/*.rb
91
- * test/blueprint.rb
92
- * test/blueprint/*.rb
93
- You can pass :root option to override framework root and :filename option to pass custom filename pattern
94
-
95
- == Setup
96
-
97
- The easiest way to install this gem for Ruby on Rails is just add this line to config/environment.rb (or config/environments/test.rb):
98
-
99
- config.gem 'blueprints', :source => 'http://gemcutter.org'
100
-
101
- If you’re not using rails, then you can install it through command line
102
-
103
- gem sources -a http://gemcutter.org
104
- sudo gem install blueprints
130
+ You can learn more about blueprint method in http://wiki.github.com/sinsiliux/blueprints/method-blueprint
105
131
 
106
- Lastly you could use it as plugin:
107
-
108
- ruby script/plugin install git://github.com/sinsiliux/blueprints.git
109
-
110
- Blueprints is activated by calling enable_blueprints. For specifics on how to call that in your testing framework see a little lower.
111
- enable_blueprints supports these parameters:
112
- * :root - custom framework root if automatic detection fails for some reason (eg. not rails/merb project)
113
- * :filename - custom files pattern with blueprints plans
114
- * :prebuild - list of blueprints plans that should be preloaded (available in all tests, never reloaded so they're much faster)
115
- * :delete_policy - set custom delete policy when deleting everything from tables (before test suite or when calling demolish). Can be :truncate or :delete, defaults to :delete
116
-
117
- === RSpec
118
-
119
- Add the following to spec_helper.rb
120
-
121
- Spec::Runner.configure do |config|
122
- ...
123
- config.enable_blueprints :filename => 'scenarios.rb', :prebuild => :preloaded_scenario
124
- end
125
-
126
- === Test::Unit
127
-
128
- Add the following lines to test_helper.rb
129
-
130
- class ActiveSupport::TestCase
131
- ...
132
- enable_blueprints
133
- end
134
-
135
- == Advanced Usage
132
+ === Advanced Usage
136
133
 
137
134
  Its just ruby, right? So go nuts:
138
135
 
139
136
  1.upto(9) do |i|
140
137
  blueprint("user_#{i}") do
141
- User.create! :name => "user#{i}"
138
+ User.blueprint :name => "user#{i}"
142
139
  end
143
140
  end
144
141
 
142
+ You can also read more about advanced usages in http://wiki.github.com/sinsiliux/blueprints/advanced-usages
143
+
145
144
  == Transactions
146
145
 
147
- Blueprints is transactional, meaning that after every test transaction is dropped and database is reset to
148
- starting point. Starting point is empty database + any scenarios that you specify in enable_blueprints.
146
+ Blueprints by default is transactional, meaning that before every test transaction is started and after every test that transaction is dropped
147
+ which resets database to the state before the test. This state is empty database + any scenarios that you specify in enable_blueprints.
149
148
 
150
149
  == TODO
151
150
 
152
- * Add ability to revert one plan.
153
- * Add preloading plans for whole block of tests.
151
+ * Add ability to revert one blueprint.
152
+ * Add preloading blueprints for whole block of tests.
154
153
  * Fix rake tasks
155
154
  * Add merb support
156
155
  * Add support for other test frameworks (check support of cucumber)
data/Rakefile CHANGED
@@ -8,6 +8,10 @@ begin
8
8
  gemspec.email = "sinsiliux@gmail.com"
9
9
  gemspec.homepage = "http://github.com/sinsiliux/blueprints"
10
10
  gemspec.authors = ["Andrius Chamentauskas"]
11
+ gemspec.bindir = 'bin'
12
+ gemspec.executables = ['blueprintify']
13
+ gemspec.add_dependency 'activesupport', '>=2.3.0'
14
+ gemspec.add_dependency 'database_cleaner', '~>0.5.0'
11
15
  end
12
16
  Jeweler::GemcutterTasks.new
13
17
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.3
1
+ 0.7.1
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'blueprints'
6
+ require 'blueprints/convertable'
7
+
8
+ options = {}
9
+
10
+ optparse = OptionParser.new do |opts|
11
+ opts.on('-s','--source-files=PATTERN', 'Define pattern for source files (used by Dir.glob)') do |files|
12
+ options[:source_files] = files
13
+ end
14
+
15
+ opts.on('-o', '--output-file=FILE', 'Define output file for converted data (used by Dir.glob)') do |file|
16
+ options[:output_file] = file
17
+ end
18
+
19
+ opts.on('-h', '--help', 'Show help (this screen)') do
20
+ puts opts
21
+ exit
22
+ end
23
+
24
+ opts.banner = "Usage: #{File.basename($0)} format --source-files=PATTERN --output-file=blueprints.rb\n"
25
+ end
26
+
27
+ begin
28
+ optparse.parse!
29
+ rescue OptionParser::ParseError => error
30
+ puts error
31
+ puts optparse.banner
32
+ exit
33
+ end
34
+
35
+ format = ARGV.shift
36
+ unless [:fixtures, :factory_girl].include?(format.to_sym)
37
+ puts "Invalid format: #{format}"
38
+ puts "Supported formats are: fixtures, factory_girl"
39
+ puts optparse.banner
40
+ exit
41
+ end
42
+
43
+ if format
44
+ converter = Blueprints::Converter.for(format).new(options)
45
+
46
+ converter.process!
47
+ else
48
+ # require 'pp'
49
+ # pp optparse
50
+ puts optparse.banner
51
+ end
52
+ # fixture_files = Dir.glob('{spec,test}/fixtures/**/*.yml')
53
+ #
54
+ # def parameterize(object)
55
+ # if object.is_a?(String)
56
+ # %Q(#{object}).inspect
57
+ # elsif object.nil?
58
+ # 'nil'
59
+ # else
60
+ # object.to_s
61
+ # end
62
+ # end
63
+ #
64
+ # fixture_files.each do |fixture_file|
65
+ # puts "Processing #{fixture_files}..."
66
+ #
67
+ # klass = File.basename(fixture_file, '.yml').singularize.capitalize
68
+ #
69
+ # loaded_yaml = YAML.load(File.read(fixture_file))
70
+ #
71
+ # blueprints = loaded_yaml.collect do |title,yaml_obj|
72
+ # params = yaml_obj.collect do |k,v|
73
+ # ":#{k} => #{parameterize(v)}"
74
+ # end.join(', ')
75
+ #
76
+ # "#{klass}.blueprint(:#{title}, {#{params}})"
77
+ # end
78
+ #
79
+ # puts "Created #{blueprints.size} blueprints: #{loaded_yaml.keys.join(', ')}."
80
+ # end
@@ -5,13 +5,15 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{blueprints}
8
- s.version = "0.6.3"
8
+ s.version = "0.7.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Andrius Chamentauskas"]
12
- s.date = %q{2010-07-03}
12
+ s.date = %q{2010-07-12}
13
+ s.default_executable = %q{blueprintify}
13
14
  s.description = %q{Another replacement for factories and fixtures. The library that lazy typists will love}
14
15
  s.email = %q{sinsiliux@gmail.com}
16
+ s.executables = ["blueprintify"]
15
17
  s.extra_rdoc_files = [
16
18
  "LICENSE",
17
19
  "README.rdoc"
@@ -22,22 +24,25 @@ Gem::Specification.new do |s|
22
24
  "README.rdoc",
23
25
  "Rakefile",
24
26
  "VERSION",
27
+ "bin/blueprintify",
25
28
  "blueprints.gemspec",
26
29
  "init.rb",
27
30
  "install.rb",
28
31
  "lib/blueprints.rb",
32
+ "lib/blueprints/blueprint.rb",
29
33
  "lib/blueprints/buildable.rb",
34
+ "lib/blueprints/configuration.rb",
30
35
  "lib/blueprints/context.rb",
31
- "lib/blueprints/database_backends/abstract.rb",
36
+ "lib/blueprints/convertable.rb",
37
+ "lib/blueprints/convertable/fixtures.rb",
32
38
  "lib/blueprints/database_backends/active_record.rb",
33
- "lib/blueprints/database_backends/none.rb",
34
39
  "lib/blueprints/errors.rb",
40
+ "lib/blueprints/extensions/deprecated.rb",
35
41
  "lib/blueprints/extensions/rspec.rb",
36
42
  "lib/blueprints/extensions/test_unit.rb",
37
43
  "lib/blueprints/file_context.rb",
38
44
  "lib/blueprints/helper.rb",
39
45
  "lib/blueprints/namespace.rb",
40
- "lib/blueprints/plan.rb",
41
46
  "lib/blueprints/root_namespace.rb",
42
47
  "spec/active_record/blueprint.rb",
43
48
  "spec/active_record/blueprints_spec.rb",
@@ -50,6 +55,9 @@ Gem::Specification.new do |s|
50
55
  "spec/no_db/blueprints_spec.rb",
51
56
  "spec/no_db/fixtures/fruit.rb",
52
57
  "spec/no_db/spec_helper.rb",
58
+ "spec/test_all.sh",
59
+ "spec/unit/configuration_spec.rb",
60
+ "spec/unit/spec_helper.rb",
53
61
  "test/blueprints_test.rb",
54
62
  "test/test_helper.rb",
55
63
  "uninstall.rb"
@@ -64,6 +72,8 @@ Gem::Specification.new do |s|
64
72
  "spec/no_db/spec_helper.rb",
65
73
  "spec/no_db/blueprints_spec.rb",
66
74
  "spec/no_db/blueprint.rb",
75
+ "spec/unit/spec_helper.rb",
76
+ "spec/unit/configuration_spec.rb",
67
77
  "spec/active_record/fixtures/fruit.rb",
68
78
  "spec/active_record/fixtures/tree.rb",
69
79
  "spec/active_record/fixtures/schema.rb",
@@ -79,9 +89,15 @@ Gem::Specification.new do |s|
79
89
  s.specification_version = 3
80
90
 
81
91
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
92
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.0"])
93
+ s.add_runtime_dependency(%q<database_cleaner>, ["~> 0.5.0"])
82
94
  else
95
+ s.add_dependency(%q<activesupport>, [">= 2.3.0"])
96
+ s.add_dependency(%q<database_cleaner>, ["~> 0.5.0"])
83
97
  end
84
98
  else
99
+ s.add_dependency(%q<activesupport>, [">= 2.3.0"])
100
+ s.add_dependency(%q<database_cleaner>, ["~> 0.5.0"])
85
101
  end
86
102
  end
87
103
 
@@ -1,81 +1,56 @@
1
1
  require 'active_support'
2
2
  require 'active_support/core_ext'
3
+ require 'database_cleaner'
3
4
  require 'set'
4
5
 
5
6
  files = %w{
6
- context buildable namespace root_namespace plan file_context helper errors
7
- database_backends/abstract database_backends/active_record database_backends/none
7
+ configuration context buildable namespace root_namespace blueprint file_context helper errors extensions/deprecated
8
8
  }
9
- files << if defined? Spec or $0 =~ /script.spec$/ or defined? RSpec
10
- 'extensions/rspec'
11
- else
12
- 'extensions/test_unit'
13
- end
14
9
  files.each {|f| require File.join(File.dirname(__FILE__), 'blueprints', f) }
15
10
 
16
11
  module Blueprints
17
- PLAN_FILES = [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
-
24
- # Returns a list of supported ORMs. For now it supports ActiveRecord and None.
25
- def self.supported_orms
26
- DatabaseBackends.constants.collect {|class_name| class_name.to_s.underscore.to_sym } - [:abstract]
27
- end
28
-
29
- # Returns root of project blueprints is used in. Automatically detected for rails and merb. Can be overwritten by using
30
- # <tt>:root</tt> options when loading blueprints. If root can't be determined, returns nil which means that current
31
- # directory is asumed as root.
32
- def self.framework_root
33
- @@framework_root ||= RAILS_ROOT rescue Rails.root rescue Merb.root rescue nil
12
+ # Contains current configuration of blueprints
13
+ def self.config
14
+ @@config ||= Blueprints::Configuration.new
34
15
  end
35
16
 
36
17
  # Setups variables from global context and starts transaction. Should be called before every test case.
37
18
  def self.setup(current_context)
38
19
  Namespace.root.setup
39
20
  Namespace.root.copy_ivars(current_context)
40
- @@orm.start_transaction
21
+ DatabaseCleaner.start if config.orm
41
22
  end
42
23
 
43
24
  # Rollbacks transaction returning everything to state before test. Should be called after every test case.
44
25
  def self.teardown
45
- @@orm.rollback_transaction
26
+ DatabaseCleaner.clean if config.orm
46
27
  end
47
28
 
48
- # Sets up configuration, clears database, runs scenarios that have to be prebuilt. Should be run before all test cases and before <tt>setup</tt>.
49
- # Accepts following options:
50
- # * <tt>:delete_policy</tt> - allows changing how tables in database should be cleared. By default simply uses delete statement. Supports :delete and :truncate options.
51
- # * <tt>:filename</tt> - Allows passing custom filename pattern in case blueprints are held in place other than spec/blueprint, test/blueprint, blueprint.
52
- # * <tt>:prebuild</tt> - Allows passing scenarios that should be prebuilt and available in all tests. Works similarly to fixtures.
53
- # * <tt>:root</tt> - Allows passing custom root folder to use in case of non rails and non merb project.
54
- # * <tt>:orm</tt> - Allows specifying what orm should be used. Default to <tt>:active_record</tt>, also allows <tt>:none</tt>
55
- def self.load(options = {})
56
- options.assert_valid_keys(:delete_policy, :filename, :prebuild, :root, :orm)
57
- options.symbolize_keys!
58
- return unless Namespace.root.empty?
29
+ # Enables blueprints support for RSpec or Test::Unit depending on whether (R)Spec is defined or not. Yields
30
+ # Blueprints::Configuration object that you can use to configure blueprints.
31
+ def self.enable
32
+ yield config if block_given?
33
+ load
34
+ extension = (defined? Spec or defined? RSpec) ? 'rspec' : 'test_unit'
35
+ require File.join(File.dirname(__FILE__), 'blueprints', 'extensions', extension)
36
+ end
59
37
 
60
- orm = (options.delete(:orm) || :active_record).to_sym
61
- raise ArgumentError, "Unsupported ORM #{orm}. Blueprints supports only #{supported_orms.join(', ')}" unless supported_orms.include?(orm)
62
- @@orm = DatabaseBackends.const_get(orm.to_s.classify).new
63
- @@orm.delete_tables(@@delete_policy = options[:delete_policy])
38
+ # Sets up configuration, clears database, runs scenarios that have to be prebuilt. Should be run before all test cases and before Blueprints#setup.
39
+ def self.load
40
+ return unless Namespace.root.empty?
64
41
 
65
- @@framework_root = options[:root] if options[:root]
66
- load_scenarios_files(options[:filename] || PLAN_FILES)
42
+ require File.join(File.dirname(__FILE__), 'blueprints', 'database_backends', config.orm.to_s) if config.orm
43
+ DatabaseCleaner.clean_with :truncation if config.orm
67
44
 
68
- Namespace.root.prebuild(options[:prebuild])
69
- end
45
+ load_scenarios_files(config.filename)
70
46
 
71
- # Clears all tables in database. Also accepts a list of tables in case not all tables should be cleared.
72
- def self.delete_tables(*tables)
73
- @@orm.delete_tables(@@delete_policy, *tables)
47
+ DatabaseCleaner.strategy = (config.transactions ? :transaction : :truncation) if config.orm
48
+ Namespace.root.prebuild(config.prebuild) if config.transactions
74
49
  end
75
50
 
76
51
  def self.backtrace_cleaner
77
52
  @backtrace_cleaner ||= ActiveSupport::BacktraceCleaner.new.tap do |bc|
78
- root_sub = /^#{@@framework_root}[\\\/]/
53
+ root_sub = /^#{config.root}[\\\/]/
79
54
  blueprints_path = File.dirname(__FILE__).sub(root_sub, '')
80
55
 
81
56
  bc.add_filter {|line| line.sub('(eval)', @@file) }
@@ -98,7 +73,7 @@ module Blueprints
98
73
  FileContext.evaluating = true
99
74
 
100
75
  patterns.flatten!
101
- patterns.collect! {|pattern| File.join(framework_root, pattern)} if framework_root
76
+ patterns.collect! {|pattern| File.join(config.root, pattern)} if config.root
102
77
 
103
78
  patterns.each do |pattern|
104
79
  unless (files = Dir.glob(pattern)).empty?
@@ -112,6 +87,6 @@ module Blueprints
112
87
  end
113
88
 
114
89
  FileContext.evaluating = false
115
- raise "Plans file not found! Put plans in #{patterns.join(' or ')} or pass custom filename pattern with :filename option"
90
+ raise "Blueprints file not found! Put blueprints in #{patterns.join(' or ')} or pass custom filename pattern with :filename option"
116
91
  end
117
92
  end