stonepath 0.0.2

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.
Files changed (54) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +26 -0
  3. data/PostInstall.txt +2 -0
  4. data/README.rdoc +58 -0
  5. data/Rakefile +44 -0
  6. data/VERSION +1 -0
  7. data/lib/stonepath/acl/controller.rb +86 -0
  8. data/lib/stonepath/acl/role.rb +53 -0
  9. data/lib/stonepath/acl/state.rb +20 -0
  10. data/lib/stonepath/acl.rb +3 -0
  11. data/lib/stonepath/config.rb +6 -0
  12. data/lib/stonepath/controller_hooks.rb +11 -0
  13. data/lib/stonepath/extensions/activerecordbase.rb +7 -0
  14. data/lib/stonepath/group.rb +9 -0
  15. data/lib/stonepath/role.rb +9 -0
  16. data/lib/stonepath/task.rb +76 -0
  17. data/lib/stonepath/work_bench.rb +11 -0
  18. data/lib/stonepath/work_item.rb +52 -0
  19. data/lib/stonepath/work_owner.rb +11 -0
  20. data/lib/stonepath.rb +50 -0
  21. data/rails_generators/stonepath/stonepath_audit_table_generator.rb +3 -0
  22. data/rails_generators/stonepath/stonepath_task_generator.rb +3 -0
  23. data/script/console +10 -0
  24. data/script/destroy +14 -0
  25. data/script/generate +14 -0
  26. data/stonepath.gemspec +117 -0
  27. data/test/acl_test.rb +17 -0
  28. data/test/app_root/app/controllers/application_controller.rb +2 -0
  29. data/test/app_root/app/models/assignment.rb +11 -0
  30. data/test/app_root/app/models/case.rb +67 -0
  31. data/test/app_root/app/models/user.rb +10 -0
  32. data/test/app_root/config/boot.rb +114 -0
  33. data/test/app_root/config/database.yml +21 -0
  34. data/test/app_root/config/environment.rb +14 -0
  35. data/test/app_root/config/environments/in_memory.rb +0 -0
  36. data/test/app_root/config/environments/mysql.rb +0 -0
  37. data/test/app_root/config/environments/postgresql.rb +0 -0
  38. data/test/app_root/config/environments/sqlite.rb +0 -0
  39. data/test/app_root/config/environments/sqlite3.rb +0 -0
  40. data/test/app_root/config/routes.rb +4 -0
  41. data/test/app_root/db/migrate/01_create_users.rb +15 -0
  42. data/test/app_root/db/migrate/02_create_assignments.rb +13 -0
  43. data/test/app_root/db/migrate/03_create_cases.rb +15 -0
  44. data/test/app_root/lib/console_with_fixtures.rb +4 -0
  45. data/test/app_root/log/.gitignore +1 -0
  46. data/test/app_root/script/console +9 -0
  47. data/test/fixtures/users.yml +7 -0
  48. data/test/group_test.rb +20 -0
  49. data/test/role_test.rb +20 -0
  50. data/test/stonepath_test.rb +11 -0
  51. data/test/test_helper.rb +31 -0
  52. data/test/workitem_test.rb +11 -0
  53. data/test/workowner_test.rb +25 -0
  54. metadata +138 -0
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2009-08-09
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,26 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/stonepath.rb
7
+ lib/stonepath/acl.rb
8
+ lib/stonepath/config.rb
9
+ lib/stonepath/controller_hooks.rb
10
+ lib/stonepath/group.rb
11
+ lib/stonepath/role.rb
12
+ lib/stonepath/task.rb
13
+ lib/stonepath/work_bench.rb
14
+ lib/stonepath/work_item.rb
15
+ lib/stonepath/work_owner.rb
16
+ lib/stonepath/acl/controller.rb
17
+ lib/stonepath/acl/role.rb
18
+ lib/stonepath/acl/state.rb
19
+ lib/stonepath/extensions/activerecordbase.rb
20
+ rails_generators/stonepath/stonepath_task_generator.rb
21
+ rails_generators/stonepath/stonepath_audit_table_generator.rb
22
+ script/console
23
+ script/destroy
24
+ script/generate
25
+ test/test_helper.rb
26
+ test/test_stonepath.rb
data/PostInstall.txt ADDED
@@ -0,0 +1,2 @@
1
+ Dave Bock is Awesome.
2
+
data/README.rdoc ADDED
@@ -0,0 +1,58 @@
1
+ = stonepath
2
+
3
+ Wednesday, August 25th UPDATE:
4
+ The extraction is underway, and I have to write some generators to have some stuff make sense outside the scope of a real application.
5
+
6
+ I'm going to have a good article on the stomepath modeling methodology shortly. It is written, it just needs diagrams and an editor's touch.
7
+
8
+
9
+ Sunday, August 9th UPDATE:
10
+ Sorry for the delay. I just gave this talk again at eRubyCon.
11
+
12
+ Some of these stateful workflow ideas are being used in a project for the
13
+ DC Public School System, but the data store there is unconventional (a
14
+ QuickBase database online), so the work being done on StonePath has taken a
15
+ back seat. I expect this project to be live again shortly, starting simply
16
+ with some wiki entries explaining the same concepts that I outline in the
17
+ presentation (including WorkItem, Ownership, Assignment, Task, Permissions, and
18
+ organizational modeling with groups and roles).
19
+
20
+ ---
21
+
22
+ This is a Stateful Workflow gem that is currently being pulled out of a
23
+ real-world client project. I'm creating the repository before RailsConf 2009
24
+ so interested people that attend my talk can watch and contribute.
25
+
26
+ I'm also asking you to keep me honest - this extraction is real, but is likely
27
+ to take a back seat to real billable client time. If I know there is interest
28
+ (that is, if I see followers and if they nag me), this project is likely to get
29
+ time over others.
30
+
31
+
32
+
33
+ gem install bokmann-stonepath
34
+
35
+ == LICENSE:
36
+
37
+ (The MIT License)
38
+
39
+ Copyright (c) 2009 FIXME full name
40
+
41
+ Permission is hereby granted, free of charge, to any person obtaining
42
+ a copy of this software and associated documentation files (the
43
+ 'Software'), to deal in the Software without restriction, including
44
+ without limitation the rights to use, copy, modify, merge, publish,
45
+ distribute, sublicense, and/or sell copies of the Software, and to
46
+ permit persons to whom the Software is furnished to do so, subject to
47
+ the following conditions:
48
+
49
+ The above copyright notice and this permission notice shall be
50
+ included in all copies or substantial portions of the Software.
51
+
52
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
53
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
54
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
55
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
56
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
57
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
58
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rcov/rcovtask'
4
+ require 'shoulda/tasks'
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gemspec|
9
+ gemspec.name = "stonepath"
10
+ gemspec.summary = "Stonepath: stateful workflow modeling for rails"
11
+ gemspec.description = "Stonepath: stateful workflow modeling for rails"
12
+ gemspec.email = "dbock@codesherpas.com"
13
+ gemspec.homepage = "http://github.com/bokmann/stonepath"
14
+ gemspec.description = "Stateful workflow modeling for Rails"
15
+ gemspec.authors = ["David Bock"]
16
+ gemspec.add_dependency('activerecord','>= 2.0.0')
17
+ end
18
+
19
+ Jeweler::GemcutterTasks.new
20
+
21
+ rescue LoadError
22
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
23
+ end
24
+
25
+ Rake::TestTask.new do |t|
26
+ t.libs << 'lib'
27
+ t.pattern = 'test/**/*_test.rb'
28
+ t.verbose = false
29
+ end
30
+
31
+
32
+ Rcov::RcovTask.new do |t|
33
+ #t.libs << "test"
34
+ #t.test_files = FileList['./test/**/test*.rb']
35
+ #t.verbose = true
36
+
37
+ t.test_files = FileList['test/**/*_test.rb']
38
+ t.verbose = true
39
+ #t.rcov_opts << "--no-color"
40
+ #t.rcov_opts << "--save coverage.info"
41
+ t.rcov_opts << "-x ^/"
42
+ end
43
+
44
+ task :default => :rcov
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,86 @@
1
+ module StonePath
2
+ module ACL
3
+ class Controller
4
+
5
+ attr_reader :guarded_class_methods
6
+ attr_reader :guarded_instance_methods
7
+ attr_reader :states
8
+ attr_reader :guarded_class
9
+ attr_reader :method_groups
10
+
11
+
12
+
13
+ def initialize(guarded_class)
14
+ @guarded_class = guarded_class
15
+ @guarded_methods = Array.new
16
+ @states = Hash.new
17
+ @method_groups = Hash.new
18
+ @aliases = Array.new
19
+ end
20
+
21
+ def guard_method(method)
22
+ @guarded_methods << method
23
+ checked_method = checked_method_name(method)
24
+ unchecked_method = unchecked_method_name(method)
25
+
26
+ guarded_class.send(:define_method, checked_method) do |*args|
27
+ if acl.allowed?(aasm_current_state, current_user, method)
28
+ self.send(unchecked_method, *args)
29
+ elsif StonePath::Config.acl_failure_mode == :exception
30
+ raise "Access Violation"
31
+ end
32
+ end
33
+
34
+ # Save our needed aliases until later
35
+ @aliases << [unchecked_method, method]
36
+ @aliases << [method, checked_method]
37
+ end
38
+
39
+ # fix up our saved aliases
40
+ def fix_aliases
41
+ @aliases.each do |src, target|
42
+ guarded_class.send(:alias_method, src, target)
43
+ end
44
+ end
45
+
46
+
47
+ def method_group(name, methods)
48
+ @method_groups[name] = methods
49
+ end
50
+
51
+ def for_state(state_name)
52
+ @states[state_name] = State.new(state_name, self) if @states[state_name].nil?
53
+ yield @states[state_name]
54
+ end
55
+
56
+ def allowed?(state, user, method)
57
+ puts "allowed called: #{state}, #{user}, #{method}"
58
+ return true
59
+ end
60
+
61
+ private
62
+
63
+ # TODO
64
+ # these two methods are ugly - we need to dry up the repetition and make them work for ? methods.
65
+ def checked_method_name(method)
66
+ method_name = method.to_s
67
+ if method_name.include?("=")
68
+ method_name.gsub!("=","")
69
+ return "#{method_name}_with_check="
70
+ else
71
+ return "#{method_name}_with_check"
72
+ end
73
+ end
74
+
75
+ def unchecked_method_name(method)
76
+ method_name = method.to_s
77
+ if method_name.include?("=")
78
+ method_name.gsub!("=","")
79
+ return "#{method_name}_without_check="
80
+ else
81
+ return "#{method_name}_without_check"
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,53 @@
1
+ module StonePath
2
+ module ACL
3
+ class Role
4
+ attr_reader :name
5
+ attr_reader :parent_state
6
+ attr_reader :allowed_methods
7
+ attr_reader :denied_methods
8
+ attr_reader :checked_methods
9
+
10
+ def initialize(name, parent_state)
11
+ @name = name
12
+ @parent_state = parent_state
13
+ @allowed_methods = Array.new
14
+ @denied_methods = Array.new
15
+ @checked_methods = Hash.new
16
+ end
17
+
18
+ def parent_acl
19
+ @parent_state.parent_acl
20
+ end
21
+
22
+ def deny_method(method)
23
+ @denied_methods << method
24
+ end
25
+
26
+ def allow_method(method)
27
+ @allowed_methods << method
28
+ end
29
+
30
+ def check_method_access(method, &check)
31
+ @checked_methods[method] = check
32
+ end
33
+
34
+ def deny_method_group(group)
35
+ parent_acl.method_groups[group].each do |method|
36
+ deny_method(method)
37
+ end
38
+ end
39
+
40
+ def allow_method_group(method_group)
41
+ parent_acl.method_groups[group].each do |method|
42
+ allow_method(method)
43
+ end
44
+ end
45
+
46
+ def check_method_group_access(method_group, &check)
47
+ parent_acl.method_groups[group].each do |method|
48
+ check_method_access(check)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,20 @@
1
+ module StonePath
2
+ module ACL
3
+ class State
4
+ attr_reader :name
5
+ attr_reader :roles
6
+ attr_reader :parent_acl
7
+
8
+ def initialize(name, parent_acl)
9
+ @name = name
10
+ @parent_acl = parent_acl
11
+ @roles = Hash.new
12
+ end
13
+
14
+ def access_for_role(role_name)
15
+ @roles[role_name] = Role.new(role_name, self) if @roles[role_name].nil?
16
+ yield @roles[role_name]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + "/acl/controller.rb"
2
+ require File.expand_path(File.dirname(__FILE__)) + "/acl/role.rb"
3
+ require File.expand_path(File.dirname(__FILE__)) + "/acl/state.rb"
@@ -0,0 +1,6 @@
1
+ module StonePath
2
+ class Config
3
+ cattr_accessor :acl_failure_mode
4
+ cattr_accessor :acl_default_access
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ module StonePath
2
+ module ControllerHooks
3
+ def self.included(base)
4
+ base.instance_eval do
5
+ before_filter do |c|
6
+ ActiveRecord::Base.current_user = current_user
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ # for the ACL stuff to work, models need to know who the current user is.
2
+ # This adds a current_user to ActiveRecord
3
+ unless ActiveRecord::Base.respond_to?(:current_user)
4
+ class ActiveRecord::Base
5
+ cattr_accessor :current_user
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module StonePath
2
+ module Group
3
+ def self.included(base)
4
+ base.instance_eval do
5
+
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module StonePath
2
+ module Role
3
+ def self.included(base)
4
+ base.instance_eval do
5
+
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,76 @@
1
+ module StonePath
2
+ module SPTask
3
+ def self.included(base)
4
+ base.instance_eval do
5
+
6
+ def assigns_to(workbench)
7
+ belongs_to :assignee, :class_name => workbench.to_s.classify
8
+ end
9
+
10
+ def task_for(workitem)
11
+ #belongs_to :workitem, :polymorphic => true
12
+ belongs_to :workitem, :class_name => workitem.to_s.classify
13
+ end
14
+
15
+ def audits_transitions
16
+ puts "#{self.class} audits transitions"
17
+ end
18
+
19
+ include AASM
20
+
21
+ #we must be attached to a workitem.
22
+ validates_presence_of :workitem
23
+
24
+ # We can have unassigned tasks.
25
+ #validates_presence_of :assignee
26
+
27
+ aasm_initial_state :active
28
+
29
+
30
+ aasm_state :active, :after_enter => :notify_created
31
+ aasm_state :completed, :before_enter => :timestamp_complete, :after_enter => :notify_closed
32
+ aasm_state :expired, :after_enter => :notify_closed
33
+ aasm_state :cancelled, :after_enter => :notify_closed
34
+
35
+
36
+ aasm_event :complete do
37
+ transitions :to => :completed, :from => :active
38
+ end
39
+
40
+ aasm_event :cancel do
41
+ transitions :to => :cancelled, :from => [:active, :completed]
42
+ end
43
+
44
+ aasm_event :expire do
45
+ transitions :to => :expired, :from => :active
46
+ end
47
+
48
+ named_scope :unassigned, lambda { { :conditions => ['assignee_id IS NULL'] } }
49
+ named_scope :active, lambda { { :conditions => ['aasm_state in (?)', ['active']] } }
50
+ named_scope :overdue, lambda { { :conditions => ['aasm_state in (?) AND due_at < ?', ['active'], Time.now] } }
51
+
52
+
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def timestamp_complete
59
+ self.completed_at = Time.now
60
+ end
61
+
62
+ def notify_created
63
+ if workitem.respond_to?(:task_created)
64
+ workitem.task_created(self)
65
+ end
66
+ end
67
+
68
+ def notify_closed
69
+ if workitem.respond_to?(:task_closed)
70
+ workitem.task_closed(self)
71
+ end
72
+ end
73
+
74
+
75
+ end
76
+ end
@@ -0,0 +1,11 @@
1
+ module StonePath
2
+ module WorkBench
3
+ def self.included(base)
4
+ base.instance_eval do
5
+ def workbench_for(tasks)
6
+ has_many tasks, :foreign_key => :assignee_id
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,52 @@
1
+ module StonePath
2
+ module WorkItem
3
+ def self.included(base)
4
+ base.instance_eval do
5
+ include AASM
6
+
7
+ def owned_by(owner)
8
+ belongs_to :owner, :class_name => owner.to_s.classify
9
+ end
10
+
11
+ def subject_of(tasks)
12
+ has_many tasks
13
+ end
14
+
15
+ def stonepath_acl()
16
+ require File.expand_path(File.dirname(__FILE__)) + "/acl.rb"
17
+ #require File.expand_path(File.dirname(__FILE__)) + "/acl/acl.rb"
18
+ #require File.expand_path(File.dirname(__FILE__)) + "/acl/acl_role.rb"
19
+ #require File.expand_path(File.dirname(__FILE__)) + "/acl/acl_state.rb"
20
+ cattr_accessor :acl
21
+ self.acl = StonePath::ACL::Controller.new(self)
22
+ yield self.acl
23
+ end
24
+
25
+ def self.define_attribute_methods_with_hook
26
+ define_attribute_methods_without_hook
27
+ acl.fix_aliases
28
+ end
29
+
30
+ class << self
31
+ alias_method "define_attribute_methods_without_hook", "define_attribute_methods"
32
+ alias_method "define_attribute_methods", "define_attribute_methods_with_hook"
33
+ end
34
+ end
35
+
36
+ def allowed?(method)
37
+ acl.allowed?(aasm_current_state, current_user, method)
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+
44
+
45
+ # if table_exists? <workitem>_transition_log_entries
46
+ #define WorkItem::TransitionLogEntry
47
+ # then for each transition method, have an after proc that
48
+ # creates workitem_transition_log
49
+ # workitem_id
50
+ # transitioned_to
51
+ # transitioned_by
52
+ # transitioned_at
@@ -0,0 +1,11 @@
1
+ module StonePath
2
+ module WorkOwner
3
+ def self.included(base)
4
+ base.instance_eval do
5
+ def workowner_for(work_items)
6
+ has_many work_items
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
data/lib/stonepath.rb ADDED
@@ -0,0 +1,50 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module StonePath
5
+ # main hook into the framework. From here, this should simply have methods that cause other includes to happen.
6
+ def self.included(base)
7
+
8
+ base.instance_eval {
9
+
10
+ def stonepath_workitem
11
+ require File.expand_path(File.dirname(__FILE__)) + "/stonepath/work_item.rb"
12
+ include StonePath::WorkItem
13
+ end
14
+
15
+ def stonepath_task
16
+ require File.expand_path(File.dirname(__FILE__)) + "/stonepath/task.rb"
17
+ include StonePath::SPTask
18
+ end
19
+
20
+ def stonepath_workbench
21
+ require File.expand_path(File.dirname(__FILE__)) + "/stonepath/work_bench.rb"
22
+ include StonePath::WorkBench
23
+ end
24
+
25
+ def stonepath_group
26
+ require File.expand_path(File.dirname(__FILE__)) + "/stonepath/group.rb"
27
+ include StonePath::Group
28
+ end
29
+
30
+ def stonepath_role
31
+ require File.expand_path(File.dirname(__FILE__)) + "/stonepath/role.rb"
32
+ include StonePath::Role
33
+ end
34
+
35
+ def stonepath_workowner
36
+ require File.expand_path(File.dirname(__FILE__)) + "/stonepath/work_owner.rb"
37
+ include StonePath::WorkOwner
38
+ end
39
+ }
40
+ end
41
+
42
+ end
43
+
44
+ require 'rubygems'
45
+ require 'activerecord'
46
+
47
+ load File.expand_path( File.dirname(__FILE__)) + "/stonepath/extensions/activerecordbase.rb"
48
+ require "stonepath/config"
49
+
50
+
@@ -0,0 +1,3 @@
1
+ class StonepathAuditTableGenerator < Rails::Generator::Base
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class StonepathTaskGenerator < Rails::Generator::Base
2
+
3
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/stonepath.rb'}"
9
+ puts "Loading stonepath gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)