Class: Hornsby

Inherits:
Object
  • Object
show all
Defined in:
lib/hornsby.rb,
lib/hornsby/errors.rb,
lib/hornsby/helper.rb,
lib/hornsby/context.rb

Defined Under Namespace

Modules: Context, Helper Classes: ScenarioNotFoundError

Constant Summary collapse

SCENARIO_FILES =
[nil, "spec", "test"].map do |dir|
  ["hornsby_scenarios", "hornsby_scenario"].map do |file|
    path = File.join([dir, file].compact)
    ["#{path}.rb", File.join(path, "*.rb")]
  end
end.flatten
@@delete_sql =
"DELETE FROM %s"
@@scenarios =

@@namespaces = {}

{}
@@executed_scenarios =
Set.new
@@global_executed_scenarios =
[]
@@global_context =
Hornsby::Context
@@context =
nil

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(scenario, &block) ⇒ Hornsby

Returns a new instance of Hornsby.



107
108
109
110
111
112
# File 'lib/hornsby.rb', line 107

def initialize(scenario, &block)
  @scenario, @parents = parse_name(scenario)
  @block = block

  @@scenarios[@scenario] = self
end

Instance Attribute Details

#scenarioObject (readonly)

Returns the value of attribute scenario.



105
106
107
# File 'lib/hornsby.rb', line 105

def scenario
  @scenario
end

Class Method Details

.build(*names) ⇒ Object



52
53
54
55
56
# File 'lib/hornsby.rb', line 52

def self.build(*names)
  scenarios = names.map {|name| @@scenarios[name.to_sym] or raise ScenarioNotFoundError, name}

  scenarios.each {|s| s.build}
end

.configure_rspec(config, options = {}) ⇒ Object



34
35
36
# File 'lib/hornsby.rb', line 34

def self.configure_rspec(config, options = {})
  raise '### This is deprecated! Please use config.enable_hornsby instead of Hornsby.configure_rspec(config)'
end

.copy_ivars(to, reload = false) ⇒ Object



101
102
103
# File 'lib/hornsby.rb', line 101

def self.copy_ivars(to, reload = false)
  @@context.copy_ivars(to, reload)
end

.delete_tables(*args) ⇒ Object



88
89
90
91
# File 'lib/hornsby.rb', line 88

def self.delete_tables(*args)
  args = tables if args.blank?
  args.each { |t| ActiveRecord::Base.connection.delete(@@delete_sql % t)  }
end

.framework_rootObject



30
31
32
# File 'lib/hornsby.rb', line 30

def self.framework_root
  @@framework_root ||= RAILS_ROOT rescue Rails.root rescue Merb.root rescue nil
end

.load(options = {}) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
# File 'lib/hornsby.rb', line 58

def self.load(options = {})
  return unless @@scenarios.empty?

  delete_tables
  @@framework_root = options[:root] if options[:root]
  load_scenarios_files(options[:filename] || SCENARIO_FILES)

  @@context = @@global_context
  @@global_scenarios = Hornsby.build(*options[:scenarios]) if options[:scenarios]
  @@global_executed_scenarios = @@executed_scenarios.to_a
end

.load_scenarios_files(*patterns) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/hornsby.rb', line 70

def self.load_scenarios_files(*patterns)
  patterns.flatten!
  patterns.collect! {|pattern| File.join(framework_root, pattern)} if framework_root
  
  patterns.each do |pattern|
    unless (files = Dir.glob(pattern)).empty?
      files.each{|f| self.module_eval File.read(f)}
      return
    end
  end
  
  raise "Scenarios file not found! Put scenarios in #{patterns.join(' or ')} or pass custom filename with :filename option"
end

.scenario(scenario, &block) ⇒ Object



84
85
86
# File 'lib/hornsby.rb', line 84

def self.scenario(scenario, &block)
  self.new(scenario, &block)
end

.setup(current_context) ⇒ Object



38
39
40
41
42
43
44
45
# File 'lib/hornsby.rb', line 38

def self.setup(current_context)
  @@context = @@global_context.clone
  @@executed_scenarios = Set.new(@@global_executed_scenarios)
  copy_ivars(current_context, true)
  ActiveRecord::Base.connection.increment_open_transactions
  ActiveRecord::Base.connection.transaction_joinable = false
  ActiveRecord::Base.connection.begin_db_transaction
end

.skip_tablesObject



97
98
99
# File 'lib/hornsby.rb', line 97

def self.skip_tables
  %w( schema_info schema_migrations )
end

.tablesObject



93
94
95
# File 'lib/hornsby.rb', line 93

def self.tables
  ActiveRecord::Base.connection.tables - skip_tables
end

.teardownObject



47
48
49
50
# File 'lib/hornsby.rb', line 47

def self.teardown
  ActiveRecord::Base.connection.rollback_db_transaction
  ActiveRecord::Base.connection.decrement_open_transactions
end

Instance Method Details

#buildObject



129
130
131
132
133
# File 'lib/hornsby.rb', line 129

def build
  build_parent_scenarios(@@context)
  build_scenario(@@context)
  self
end

#build_parent_scenarios(context) ⇒ Object



140
141
142
143
144
145
146
147
# File 'lib/hornsby.rb', line 140

def build_parent_scenarios(context)
  @parents.each do |p|
    parent = @@scenarios[p] or raise ScenarioNotFoundError, p

    parent.build_parent_scenarios(context)
    parent.build_scenario(context)
  end
end

#build_scenario(context) ⇒ Object



135
136
137
138
# File 'lib/hornsby.rb', line 135

def build_scenario(context)
  surface_errors { context.execute(&@block) } unless @@executed_scenarios.include?(@scenario)
  @@executed_scenarios << @scenario
end

#parse_name(name) ⇒ Object



114
115
116
117
118
119
120
121
122
123
# File 'lib/hornsby.rb', line 114

def parse_name(name)
  case name
    when Hash
      return name.keys.first.to_sym, [name.values.first].flatten.map{|sc| parse_name(sc).first}
    when Symbol, String
      return name.to_sym, []
    else
      raise TypeError, "Pass scenarios names as strings or symbols only, cannot build scenario '#{name.inspect}'"
  end  
end

#say(*messages) ⇒ Object



125
126
127
# File 'lib/hornsby.rb', line 125

def say(*messages)
  puts messages.map { |message| "=> #{message}" }
end

#surface_errorsObject



149
150
151
152
153
154
155
156
157
158
# File 'lib/hornsby.rb', line 149

def surface_errors
  yield
rescue StandardError => error
  puts
  say "There was an error building scenario '#{@scenario}'", error.inspect
  puts
  puts error.backtrace
  puts
  raise error
end