blueprints 0.6.3 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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