openrain-scenarios 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,61 @@
1
+ scenarios
2
+ =========
3
+
4
+ The idea behind 'scenarios' is simple. Scenarions are basically just organized bits of arbitrary ruby code.
5
+
6
+
7
+ why?
8
+ ----
9
+
10
+ Here's why scenarios were originally written ... you may use them however you wish!
11
+
12
+ I had a Rails application and I wanted to be able to do something like this:
13
+
14
+ $ rake scenarios:load SCENARIO=one_thousand_users
15
+
16
+ ... which would put 1,000 users in the database.
17
+
18
+ Sometimes, while testing out my application's functionality in a browser, I would
19
+ want to setup some scenario to test. Maybe I'm working on X feature and it would
20
+ be helpful if I had Y data in the database to work with. Typically, I would
21
+ open up `script/console` and create abunchof Y data manually. But ... wouldn't it
22
+ be useful if we could automate that?
23
+
24
+ Also, our application requires *some* data to be in the database for the app to
25
+ load properly. So we created a scenario that loads up the minimum amount of
26
+ data required to run the app!
27
+
28
+
29
+ how?
30
+ ----
31
+
32
+ $ sudo gem install remi-scenarios -s http://gems.github.com
33
+
34
+ then, if you're in a Rails project ...
35
+
36
+ $ ./script/generate scenario Foo
37
+
38
+ to see all defined scenarios ...
39
+
40
+ $ rake scenarios
41
+
42
+ to load a particular scenario ...
43
+
44
+ $ rake scenarios:load NAME=my_scenario
45
+ $ rake scenarios:load NAME=my_scenario,and_some_more_scenarios
46
+
47
+
48
+ what else?
49
+ ----------
50
+
51
+ more documentation to come soon!
52
+
53
+
54
+ TODO
55
+ ----
56
+
57
+ - i forgot to import the `scenarios` method so it's accessible from test / specs ... fix!
58
+ - make the scenario directory for the generator configurable (and that dir should always be included in the Scenario loadpath
59
+ - make all scenarios load within a specific context and add hooks so people can update/modify that context
60
+ - write a spec to make sure that the load paths work properly and multiple directories can have scenarios with the same name ... the directories added last should override the previous ones. also make sure paths are uniq ... if i add 'foo' and 'foo' is already there, it should make foo the last path (move it to the end)
61
+ - make sure this works when --trace is called
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rake'
2
+ require 'rubygems'
3
+ require 'rake/rdoctask'
4
+ require 'spec/rake/spectask'
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |s|
9
+ s.name = "scenarios"
10
+ s.summary = "Create, Organize, and Run arbitrary snippets of Ruby code"
11
+ s.email = "remi@remitaylor.com"
12
+ s.homepage = "http://github.com/remi/scenarios"
13
+ s.description = "Create, Organize, and Run arbitrary snippets of Ruby code"
14
+ s.authors = %w( remi )
15
+ s.files = FileList["[A-Z]*", "{lib,spec,examples,rails_generators}/**/*"]
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
+ end
20
+
21
+ Spec::Rake::SpecTask.new do |t|
22
+ t.spec_files = FileList['spec/**/*_spec.rb']
23
+ end
24
+
25
+ desc "Run all examples with RCov"
26
+ Spec::Rake::SpecTask.new('rcov') do |t|
27
+ t.spec_files = FileList['spec/**/*_spec.rb']
28
+ t.rcov = true
29
+ end
30
+
31
+ Rake::RDocTask.new do |rdoc|
32
+ rdoc.rdoc_dir = 'rdoc'
33
+ rdoc.title = 'scenarios'
34
+ rdoc.options << '--line-numbers' << '--inline-source'
35
+ rdoc.rdoc_files.include('README*')
36
+ rdoc.rdoc_files.include('lib/**/*.rb')
37
+ end
38
+
39
+ desc 'Confirm that gemspec is $SAFE'
40
+ task :safe do
41
+ require 'yaml'
42
+ require 'rubygems/specification'
43
+ data = File.read('scenarios.gemspec')
44
+ spec = nil
45
+ if data !~ %r{!ruby/object:Gem::Specification}
46
+ Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
47
+ else
48
+ spec = YAML.load(data)
49
+ end
50
+ spec.validate
51
+ puts spec
52
+ puts "OK"
53
+ end
54
+
55
+ task :default => :spec
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 2
@@ -0,0 +1,2 @@
1
+ # foo!
2
+ $set_by_foo = 'hello from foo!'
@@ -0,0 +1,4 @@
1
+ # i am the description
2
+ # only the first line
3
+ # should be included in the description
4
+ $set_by_first_scenario = 'hello from first scenario!'
@@ -0,0 +1,64 @@
1
+ # here be rake tasks for scenarios
2
+ #
3
+ # you can get them in your Rakefile by:
4
+ # require 'scenarios/tasks'
5
+ # Scenario.load_paths = [ 'path/to/my/scenarios/**/*' ]
6
+
7
+ require 'scenarios'
8
+
9
+ desc 'Print all available scenarios'
10
+ task :scenarios do
11
+ if Scenario.all.empty?
12
+ puts "there are no scenarios. add some to one of the Scenario.load_paths: #{ Scenario.load_paths.inspect }"
13
+ else
14
+ Scenario.all.each do |scenario|
15
+ puts "#{ scenario.name }: #{ scenario.description }"
16
+ end
17
+ end
18
+ end
19
+
20
+ namespace :scenarios do
21
+
22
+ desc 'scenarios:load NAME=foo OR NAME=a,b,c'
23
+ task :load => ( (defined?RAILS_ENV) ? :environment : nil ) do
24
+ puts "called scenarios:load" if Scenario.verbose
25
+ if ENV['NAME']
26
+ names = ENV['NAME'].split(',')
27
+ puts "Scenario.load #{ names.inspect }" if Scenario.verbose
28
+ Scenario.load *names
29
+ else
30
+ puts "you need to pass NAME=scenario_name to load a scenario"
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ =begin
37
+ if defined?RAILS_ENV
38
+ # rails-specific task
39
+
40
+ desc 'this will clear the database, load scenarios, & run the site'
41
+ task :run => :environment do
42
+ if RAILS_ENV == 'test'
43
+ if ENV['NAME']
44
+
45
+ puts "clearing database ..."
46
+ Rake::Task[:truncate].invoke # this isn't defined in scenarios! need to not call this or include a :truncate task
47
+
48
+ puts "loading scenarios ..."
49
+ names = ENV['NAME'].split(',')
50
+ Scenario.load *names
51
+
52
+ puts "running the site ..."
53
+ require 'commands/server'
54
+
55
+ else
56
+ puts "Usage: rake:run NAME=the_names,of_some,scenarios_to_load RAILS_ENV=test"
57
+ end
58
+ else
59
+ puts "sorry, i'm not comfortable doing this in any environment but 'test'"
60
+ end
61
+ end
62
+
63
+ end
64
+ =end
data/lib/scenarios.rb ADDED
@@ -0,0 +1,143 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ # a Scenario is some set of data/logic that can be loaded up easily
4
+ # to run an application against.
5
+ #
6
+ # if you need to enter abunchof data manually into the a website
7
+ # to test something you're working on, this is a good candidate for
8
+ # a scenario.
9
+ #
10
+ # we can also use scenarios for loading up the base foundation of
11
+ # data that's required to load the web application
12
+ #
13
+ # TODO define what is public/private and document public API in README and
14
+ # actually give private methods a private visibility
15
+ #
16
+ class Scenario
17
+
18
+ attr_accessor :file_path
19
+
20
+ def initialize file_path
21
+ @file_path = file_path
22
+ end
23
+
24
+ def name
25
+ File.basename(file_path).sub(/\.rb$/, '')
26
+ end
27
+ alias to_s name
28
+
29
+ # if the first line of the scenario's source code
30
+ # is a comment, we use it as the scenario's description
31
+ #
32
+ # ideally, all scenarios should have a short simple description
33
+ #
34
+ def description
35
+ if first_line =~ /^#/
36
+ first_line.sub(/^#*/, '').strip
37
+ else
38
+ ''
39
+ end
40
+ end
41
+
42
+ def first_line
43
+ source_code.split("\n").first
44
+ end
45
+
46
+ def source_code
47
+ File.read file_path
48
+ end
49
+
50
+ # evaluates the code of the scenario
51
+ def load
52
+ self.class.load self # pass the loading off to the class
53
+ end
54
+
55
+ class << self
56
+
57
+ # an array of the paths where scenarios can be found
58
+ #
59
+ # any .rb file found in these directories is assumed to
60
+ # be a scenario
61
+ #
62
+ attr_accessor :load_paths, :verbose, :before_blocks
63
+
64
+ # returns all Scenarios found using Scenario#load_paths
65
+ def all
66
+ load_paths.inject([]) do |all_scenarios, load_path|
67
+ Dir[ File.join(load_path, '**', '*.rb') ].each do |found_scenario_file|
68
+ all_scenarios << Scenario.new(found_scenario_file)
69
+ end
70
+ all_scenarios
71
+ end
72
+ end
73
+
74
+ def verbose= value
75
+ if value == true && @verbose != true
76
+ puts "Scenario verbose enable."
77
+ puts "Scenario load_paths => #{ Scenario.load_paths.inspect }"
78
+ puts "#{ Scenario.all.length } scenario(s) found"
79
+ end
80
+ @verbose = value
81
+ end
82
+
83
+ # run some block of code before any scenarios run
84
+ #
85
+ # good for last-minute require statements and whatnot
86
+ #
87
+ def before &block
88
+ @before_blocks ||= []
89
+ @before_blocks << block if block
90
+ end
91
+
92
+ # returns a scenario by name, eg. Scenario[:foo]
93
+ #
94
+ # if 1 name is passed in, we'll return that scenario or nil
95
+ #
96
+ # if more than 1 name is passed in, we'll return an array of
97
+ # scenarios (or an empty array)
98
+ #
99
+ def [] *names
100
+ puts "looking for scenario(s) with name(s): #{ names.inspect }" if Scenario.verbose
101
+ if names.length == 1
102
+ puts "all scenario names: #{ all.map(&:name) }" if Scenario.verbose
103
+ puts "btw, the load paths are: #{ load_paths.inspect }" if Scenario.verbose
104
+ all.find {|scenario| scenario.name.downcase == names.first.to_s.downcase }
105
+ else
106
+ names.map {|name| self[ name ] }.compact
107
+ end
108
+ end
109
+
110
+ # loads a Scenario, evaluating its code
111
+ #
112
+ # we do this here so we can easily eval in a certain context,
113
+ # if we want to add a context later
114
+ #
115
+ # Scenario.load @scenario1, @scenario2
116
+ # Scenario.load :names, 'work', :too
117
+ #
118
+ def load *scenarios
119
+ puts "called Scenario.load with scenarios #{ scenarios.inspect }" if Scenario.verbose
120
+ @before_blocks.each { |b| b.call } if @before_blocks and not @before_blocks.empty?
121
+ # TODO should be able to define some block that scenarios get evaluated in!
122
+ # or some things that scenarios might want to require or ...
123
+ scenarios.each do |scenario|
124
+ scenario = self[scenario] unless scenario.is_a?Scenario # try getting using self[] if not a scenario
125
+ puts "loading #{ scenario.name } (#{ scenario.description })" if Scenario.verbose && scenario.is_a?(Scenario)
126
+ begin
127
+ if scenario.is_a?Scenario
128
+ puts "eval'ing scenario: #{ scenario.inspect }" if Scenario.verbose
129
+ eval scenario.source_code
130
+ else
131
+ puts "Unsure how to load scenario: #{ scenario.inspect }"
132
+ end
133
+ rescue => ex
134
+ raise "An Exception was thrown by scenario: #{ scenario.name }\n\n#{ ex }"
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ Scenario.load_paths ||= [ 'scenarios' ] # default to a 'scenarios' directory relative to your current location
141
+ Scenario.verbose = false
142
+
143
+ end
@@ -0,0 +1,5 @@
1
+ Description:
2
+ Creates a new scenario
3
+
4
+ Examples:
5
+ `./script/generate scenario Foo`
@@ -0,0 +1,44 @@
1
+ # This generator creates a new 'scenario'
2
+ class ScenarioGenerator < Rails::Generator::Base
3
+
4
+ attr_accessor :name_of_scenario_to_create, :name_of_scenario_file_to_create
5
+
6
+ # `./script/generate scenario foo` will result in:
7
+ #
8
+ # runtime_args: ['foo']
9
+ # runtime_options: {:quiet=>false, :generator=>"scenario", :command=>:create, :collision=>:ask}
10
+ #
11
+ def initialize(runtime_args, runtime_options = {})
12
+ setup_rails_to_run_scenarios
13
+ @name_of_scenario_to_create = runtime_args.join(' ')
14
+ @name_of_scenario_file_to_create = runtime_args.join('_').downcase
15
+ super
16
+ end
17
+
18
+ # this should be done by ./script/generate blackbox
19
+ def setup_rails_to_run_scenarios
20
+ rakefile = File.join RAILS_ROOT, 'Rakefile'
21
+ if File.file? rakefile
22
+ source = File.read rakefile
23
+ unless source =~ /require .scenarios.tasks./
24
+ File.open( rakefile, 'a' ) do |f|
25
+ f << %[require 'scenarios/tasks']
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def manifest
32
+ record do |m|
33
+ m.directory 'scenarios'
34
+ m.template 'scenario.erb', "scenarios/#{ name_of_scenario_file_to_create }.rb"
35
+ end
36
+ end
37
+
38
+ protected
39
+
40
+ def banner
41
+ "Usage: #{$0} _scenario Name of Scenario to Create"
42
+ end
43
+
44
+ end
@@ -0,0 +1,5 @@
1
+ # my one-line description of the <%= name_of_scenario_to_create %> scenario
2
+
3
+ $foo = "the <%= name_of_scenario_file_to_create %> scenario sets a global variable!"
4
+
5
+ puts "Hello from the <%= name_of_scenario_to_create %> scenario!"
@@ -0,0 +1,112 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ # this isn't exactly a model ... just something that helps
4
+ # with out development and speccing
5
+ describe Scenario do
6
+
7
+ def path_to_test_scenarios
8
+ File.join File.dirname(__FILE__), '..', 'examples', 'scenarios'
9
+ end
10
+ def path_to_more_scenarios
11
+ File.join File.dirname(__FILE__), '..', 'examples', 'more_scenarios'
12
+ end
13
+
14
+ before do
15
+ Scenario.load_paths = [ path_to_test_scenarios ]
16
+ $set_by_first_scenario = nil
17
+ $set_by_foo = nil
18
+ end
19
+
20
+ before :all do
21
+ @original_scenario_paths = Scenario.load_paths
22
+ end
23
+ after :all do
24
+ Scenario.load_paths = @original_scenario_paths
25
+ end
26
+
27
+ it 'should find scenario files properly' do
28
+ Scenario.load_paths = []
29
+ Scenario.all.should be_empty
30
+
31
+ Scenario.load_paths = [ path_to_test_scenarios ]
32
+ Scenario.all.length.should == 1
33
+ Scenario.all.first.name.should == 'first'
34
+
35
+ Scenario.load_paths << path_to_more_scenarios
36
+ Scenario.all.length.should == 2
37
+ Scenario.all.map(&:name).should include('first')
38
+ Scenario.all.map(&:name).should include('foo')
39
+ end
40
+
41
+ it 'should be easy to get a scenario by name' do
42
+ Scenario[:first].name.should == 'first'
43
+ Scenario['first'].name.should == 'first'
44
+
45
+ Scenario[:foo].should be_nil
46
+ Scenario.load_paths << path_to_more_scenarios
47
+ Scenario[:foo].should_not be_nil
48
+ end
49
+
50
+ it 'should be easy to get multiple scenarios by name' do
51
+ Scenario[:first, :nonexistent, :notfound].length.should == 1
52
+ Scenario[:first, :nonexistent, :notfound].first.name.should == 'first'
53
+
54
+ Scenario[:first, :nonexistent, :foo].length.should == 1
55
+ Scenario.load_paths << path_to_more_scenarios
56
+ Scenario[:first, :nonexistent, :foo].length.should == 2
57
+ Scenario[:first, :nonexistent, :foo].map(&:name).should include('first')
58
+ Scenario[:first, :nonexistent, :foo].map(&:name).should include('foo')
59
+ end
60
+
61
+ it 'should have a name' do
62
+ Scenario.all.first.should be_a_kind_of(Scenario)
63
+ Scenario.all.first.name.should == 'first'
64
+ end
65
+
66
+ it 'should have a description' do
67
+ Scenario.all.first.description.should == 'i am the description'
68
+ end
69
+
70
+ it 'should be loadable' do
71
+ $set_by_first_scenario.should be_nil
72
+ Scenario[:first].load
73
+ $set_by_first_scenario.should == 'hello from first scenario!'
74
+ end
75
+
76
+ it 'should be able to load multiple scenarios' do
77
+ Scenario.load_paths << path_to_more_scenarios
78
+
79
+ $set_by_first_scenario.should be_nil
80
+ $set_by_foo.should be_nil
81
+
82
+ Scenario[:first, :foo].each {|scenario| scenario.load }
83
+
84
+ $set_by_first_scenario.should == 'hello from first scenario!'
85
+ $set_by_foo.should == 'hello from foo!'
86
+ end
87
+
88
+ it 'should be really easy to load multiple scenarios' do
89
+ Scenario.load_paths << path_to_more_scenarios
90
+
91
+ $set_by_first_scenario.should be_nil
92
+ $set_by_foo.should be_nil
93
+
94
+ Scenario.load :first, :foo
95
+
96
+ $set_by_first_scenario.should == 'hello from first scenario!'
97
+ $set_by_foo.should == 'hello from foo!'
98
+ end
99
+
100
+ it 'to_s should be the scenario name' do
101
+ Scenario[:first].to_s.should == 'first'
102
+ end
103
+
104
+ it 'should allow globbing in load_paths' do
105
+ Scenario.load_paths = [ File.join(File.dirname(__FILE__), '..', 'examp*', '**') ]
106
+
107
+ Scenario.all.length.should == 2
108
+ Scenario.all.map(&:name).should include('first')
109
+ Scenario.all.map(&:name).should include('foo')
110
+ end
111
+
112
+ end
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/../lib/scenarios'
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: openrain-scenarios
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - remi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-03 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Create, Organize, and Run arbitrary snippets of Ruby code
17
+ email: remi@remitaylor.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - MIT-LICENSE
26
+ - Rakefile
27
+ - VERSION.yml
28
+ - README.markdown
29
+ - lib/scenarios
30
+ - lib/scenarios/tasks.rb
31
+ - lib/scenarios.rb
32
+ - spec/scenario_spec.rb
33
+ - spec/spec_helper.rb
34
+ - examples/scenarios
35
+ - examples/scenarios/first.rb
36
+ - examples/more_scenarios
37
+ - examples/more_scenarios/foo.rb
38
+ - rails_generators/scenario
39
+ - rails_generators/scenario/USAGE
40
+ - rails_generators/scenario/scenario_generator.rb
41
+ - rails_generators/scenario/templates
42
+ - rails_generators/scenario/templates/scenario.erb
43
+ has_rdoc: true
44
+ homepage: http://github.com/openrain/scenarios
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --inline-source
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.2.0
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: Create, Organize, and Run arbitrary snippets of Ruby code
70
+ test_files: []
71
+