reactive-dev 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +3 -0
- data/LICENSE +21 -0
- data/Manifest +29 -0
- data/README +130 -0
- data/Rakefile +19 -0
- data/app_generators/reactive/USAGE +14 -0
- data/app_generators/reactive/reactive_generator.rb +137 -0
- data/app_generators/reactive/templates/README +101 -0
- data/app_generators/reactive/templates/Rakefile +16 -0
- data/app_generators/reactive/templates/config/boot.rb +118 -0
- data/app_generators/reactive/templates/config/config.rb +29 -0
- data/app_generators/reactive/templates/config/empty.log +0 -0
- data/app_generators/reactive/templates/script/console +47 -0
- data/app_generators/reactive/templates/script/destroy +18 -0
- data/app_generators/reactive/templates/script/generate +18 -0
- data/app_generators/reactive/templates/script/run +9 -0
- data/app_generators/reactive/templates/script/win_script.cmd +1 -0
- data/bin/reactive +15 -0
- data/lib/reactive-dev.rb +3 -0
- data/lib/reactive-dev/code_statistics.rb +107 -0
- data/lib/reactive-dev/generated_attribute.rb +40 -0
- data/lib/reactive-dev/named_base_generator.rb +79 -0
- data/lib/reactive-dev/rubigen_plugin_sources.rb +49 -0
- data/lib/reactive-dev/source_annotation_extractor.rb +62 -0
- data/lib/reactive-dev/tasks/annotations.rake +23 -0
- data/lib/reactive-dev/tasks/app.rake +51 -0
- data/lib/reactive-dev/tasks/plugin.rb +147 -0
- data/lib/reactive-dev/tasks/statistics.rake +7 -0
- data/lib/reactive-dev/tasks/testing.rake +118 -0
- metadata +129 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
|
+
# and they will automatically be available to Rake.
|
3
|
+
|
4
|
+
APP_PATH = File.dirname(__FILE__)
|
5
|
+
APP_NAME = APP_PATH.split('/').last
|
6
|
+
|
7
|
+
require ["#{File.dirname(__FILE__)}/config/boot.rb", "#{File.dirname(__FILE__)}/boot.rb"].find {|path| File.file? path}
|
8
|
+
Reactive.load(['--root', APP_PATH])
|
9
|
+
Reactive::Initializer.stages.delete(:check_plugins)
|
10
|
+
Reactive.init(:configure)
|
11
|
+
|
12
|
+
require 'rake'
|
13
|
+
require 'rake/testtask'
|
14
|
+
require 'rake/rdoctask'
|
15
|
+
|
16
|
+
require 'reactive-core/tasks/reactive'
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Reactive
|
2
|
+
class << self
|
3
|
+
def load(argv = ARGV)
|
4
|
+
return @bootstrapper if @bootstrapper
|
5
|
+
options = {}
|
6
|
+
options[:root_dir] = if index = argv.rindex(argv.find {|arg| arg == '--root' })
|
7
|
+
argv[index+1]
|
8
|
+
end
|
9
|
+
options[:config_file] = if index = argv.rindex(argv.find {|arg| arg == '--config-file' })
|
10
|
+
argv[index+1]
|
11
|
+
end
|
12
|
+
@argv = argv
|
13
|
+
@bootstrapper ||= Bootstrapper.new(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def loaded?
|
17
|
+
@bootstrapper
|
18
|
+
end
|
19
|
+
|
20
|
+
def init(stage = :final, argv = @argv || ARGV)
|
21
|
+
load(argv)
|
22
|
+
Reactive::Initializer.run(stage, Configuration.new(argv))
|
23
|
+
end
|
24
|
+
|
25
|
+
def run(argv = @argv || ARGV)
|
26
|
+
init(:final, argv)
|
27
|
+
Dispatcher::Base.dispatch(Reactive.configuration.initial_request.is_a?(Hash) ? Request.new(Reactive.configuration.initial_request) : Reactive.configuration.initial_request)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Bootstrapper
|
32
|
+
def initialize(options)
|
33
|
+
@config_file = options[:config_file]
|
34
|
+
@root_dir = File.expand_path(options[:root_dir]) if options[:root_dir]
|
35
|
+
load_rubygems
|
36
|
+
|
37
|
+
# add apps gem directory to load path
|
38
|
+
if @root_dir
|
39
|
+
Gem.clear_paths
|
40
|
+
Gem.path.unshift("#{@root_dir}/gems")
|
41
|
+
end
|
42
|
+
|
43
|
+
load_reactive_gem
|
44
|
+
require 'reactive-core/initializer'
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_reactive_gem
|
48
|
+
# load activesupport first
|
49
|
+
begin
|
50
|
+
if version = activesupport_gem_version
|
51
|
+
gem 'activesupport', version
|
52
|
+
end
|
53
|
+
rescue Gem::LoadError => load_error
|
54
|
+
$stderr.puts "Missing the activesupport #{version} gem. Either install the required version or choose an appropriate value for the ACTIVESUPPORT_GEM_VERSION setting in config/config.rb"
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
|
58
|
+
if version = reactive_gem_version
|
59
|
+
gem 'reactive-core', version
|
60
|
+
else
|
61
|
+
gem 'reactive-core'
|
62
|
+
end
|
63
|
+
rescue Gem::LoadError => load_error
|
64
|
+
$stderr.puts "Missing the reactive-core #{version} gem. Please `gem install -v=#{version} reactive-core`, update your REACTIVE_GEM_VERSION setting in config/config.rb for the Reactive version you do have installed, or comment out REACTIVE_GEM_VERSION to use the latest version installed."
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
def rubygems_version
|
69
|
+
Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
|
70
|
+
end
|
71
|
+
|
72
|
+
def reactive_gem_version
|
73
|
+
if defined? REACTIVE_GEM_VERSION
|
74
|
+
REACTIVE_GEM_VERSION
|
75
|
+
elsif ENV.include?('REACTIVE_GEM_VERSION')
|
76
|
+
ENV['REACTIVE_GEM_VERSION']
|
77
|
+
else
|
78
|
+
parse_gem_version('reactive', read_config_rb)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def activesupport_gem_version
|
83
|
+
parse_gem_version('activesupport', read_config_rb)
|
84
|
+
end
|
85
|
+
|
86
|
+
def load_rubygems
|
87
|
+
require 'rubygems'
|
88
|
+
|
89
|
+
unless rubygems_version >= '1.1.0'
|
90
|
+
$stderr.puts "Reactive requires RubyGems >= 1.1.0 (you have #{rubygems_version}). Please `gem update --system` and try again."
|
91
|
+
exit 1
|
92
|
+
end
|
93
|
+
|
94
|
+
rescue LoadError
|
95
|
+
$stderr.puts "Reactive requires RubyGems >= 1.1.0. Please install RubyGems and try again: http://rubygems.rubyforge.org"
|
96
|
+
exit 1
|
97
|
+
end
|
98
|
+
|
99
|
+
def parse_gem_version(gem_name, text)
|
100
|
+
$1 if text =~ Regexp.new(%Q{^[^#]*#{gem_name.upcase}_GEM_VERSION\\s*=\\s*["']([!~<>=]*\\s*[\\d.]+)["']})
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
def read_config_rb
|
105
|
+
return if @config_rb
|
106
|
+
files = [
|
107
|
+
@config_file,
|
108
|
+
@root_dir ? "#{@root_dir}/config/config.rb" : nil,
|
109
|
+
@root_dir ? "#{@root_dir}/config.rb" : nil,
|
110
|
+
"config.rb"
|
111
|
+
].compact.select {|name| File.file? name}
|
112
|
+
|
113
|
+
raise StandardError, "No config file found, you may specify it with --config-file" if files.empty?
|
114
|
+
@config_rb = File.read(files.first)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# You may specify the activesupport gem version that will be used.
|
2
|
+
# It is provided to resolve dependency issues. Note that the minimum version is 2.0.0
|
3
|
+
# ACTIVESUPPORT_GEM_VERSION = "= 2.0.2"
|
4
|
+
|
5
|
+
# You may also specifiy the Reactive gem version to use
|
6
|
+
# REACTIVE_GEM_VERSION = ">= 0.2.0"
|
7
|
+
|
8
|
+
with Reactive.configuration do |config|
|
9
|
+
# Don't forget to specify the default dispatcher which is one of your plugins, ex:
|
10
|
+
# config.dispatcher.default_dispatcher = :mvc
|
11
|
+
# You also have to configure an inital request like so:
|
12
|
+
# config.initial_request = {:controller => 'application', :action => 'initial', :format => :wx}
|
13
|
+
|
14
|
+
# put the .gem statements in the order you want them loaded.
|
15
|
+
# You may add a version requirement for each of the gems, like:
|
16
|
+
# config.gem 'reactive-mvc', '>=0.2.0'
|
17
|
+
<% for plugin in plugins -%>
|
18
|
+
config.gem '<%= plugin %>'<% end %>
|
19
|
+
|
20
|
+
config.app_gem_spec do |s|
|
21
|
+
s.name = "<%= app_name %>"
|
22
|
+
s.version = "1.0.0"
|
23
|
+
s.author = "Your name"
|
24
|
+
s.email = "you@there.com"
|
25
|
+
s.homepage = "http://there.com"
|
26
|
+
s.summary = "My great application"
|
27
|
+
s.description = "Visit our website for further information"
|
28
|
+
end
|
29
|
+
end
|
File without changes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
boot_location = [
|
4
|
+
["#{File.dirname(__FILE__)}/../config/boot.rb", ".."],
|
5
|
+
["#{File.dirname(__FILE__)}/boot.rb", "."]
|
6
|
+
].find{|path, root| File.file? path}
|
7
|
+
|
8
|
+
require boot_location.first
|
9
|
+
Reactive.load(['--root', File.join(File.dirname(__FILE__), boot_location.last)])
|
10
|
+
|
11
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
12
|
+
|
13
|
+
require 'optparse'
|
14
|
+
|
15
|
+
options = { :sandbox => false, :irb => irb }
|
16
|
+
OptionParser.new do |opt|
|
17
|
+
opt.banner = "Usage: console [environment] [options]"
|
18
|
+
opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |v| options[:irb] = v }
|
19
|
+
opt.on("--debugger", 'Enable ruby-debugging for the console.') { |v| options[:debugger] = v }
|
20
|
+
opt.parse!(ARGV)
|
21
|
+
end
|
22
|
+
|
23
|
+
libs = " -r irb/completion"
|
24
|
+
libs << %( -r "#{boot_location.first}")
|
25
|
+
libs << %( -r "#{Gem.loaded_specs['reactive-core'].full_gem_path}/lib/reactive-core/console_app")
|
26
|
+
|
27
|
+
if options[:debugger]
|
28
|
+
begin
|
29
|
+
require 'ruby-debug'
|
30
|
+
libs << " -r ruby-debug"
|
31
|
+
puts "=> Debugger enabled"
|
32
|
+
rescue Exception
|
33
|
+
puts "You need to install ruby-debug to run the console in debugging mode. With gems, use 'gem install ruby-debug'"
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
ENV['REACTIVE_ENV'] = case ARGV.first
|
39
|
+
when "p"; "production"
|
40
|
+
when "d"; "development"
|
41
|
+
when "t"; "test"
|
42
|
+
else
|
43
|
+
ARGV.first || ENV['REACTIVE_ENV'] || 'development'
|
44
|
+
end
|
45
|
+
|
46
|
+
puts "Loading #{ENV['REACTIVE_ENV']} environment (Reactive #{Reactive::VERSION::STRING})"
|
47
|
+
exec "#{options[:irb]} #{libs} --simple-prompt"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
boot_location = [
|
4
|
+
["#{File.dirname(__FILE__)}/../config/boot.rb", ".."],
|
5
|
+
["#{File.dirname(__FILE__)}/boot.rb", "."]
|
6
|
+
].find{|path, root| File.file? path}
|
7
|
+
|
8
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), boot_location.last))
|
9
|
+
require boot_location.first
|
10
|
+
|
11
|
+
Reactive.init(:configure, ARGV + ['--root', APP_ROOT])
|
12
|
+
|
13
|
+
require 'rubigen'
|
14
|
+
require 'rubigen/scripts/destroy'
|
15
|
+
|
16
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
17
|
+
RubiGen::Base.use_plugin_sources! [:reactive, :reactive_app, :test_unit]
|
18
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
boot_location = [
|
4
|
+
["#{File.dirname(__FILE__)}/../config/boot.rb", ".."],
|
5
|
+
["#{File.dirname(__FILE__)}/boot.rb", "."]
|
6
|
+
].find{|path, root| File.file? path}
|
7
|
+
|
8
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), boot_location.last))
|
9
|
+
require boot_location.first
|
10
|
+
|
11
|
+
Reactive.init(:configure, ARGV + ['--root', APP_ROOT])
|
12
|
+
|
13
|
+
require 'rubigen'
|
14
|
+
require 'rubigen/scripts/generate'
|
15
|
+
|
16
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
17
|
+
RubiGen::Base.use_plugin_sources! [:reactive, :reactive_app, :test_unit]
|
18
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
boot_location = [
|
4
|
+
["#{File.dirname(__FILE__)}/../config/boot.rb", ".."],
|
5
|
+
["#{File.dirname(__FILE__)}/boot.rb", "."]
|
6
|
+
].find{|path, root| File.file? path}
|
7
|
+
|
8
|
+
require boot_location.first
|
9
|
+
Reactive.run(ARGV + ['--root', File.join(File.dirname(__FILE__), boot_location.last)])
|
@@ -0,0 +1 @@
|
|
1
|
+
@ruby <%= File.join("script", filename) %> %*
|
data/bin/reactive
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'reactive-core/version'
|
5
|
+
if %w(--version -v).include? ARGV.first
|
6
|
+
puts "Reactive #{Reactive::VERSION::STRING}"
|
7
|
+
exit(0)
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'reactive-dev'
|
11
|
+
require 'rubigen'
|
12
|
+
require 'rubigen/scripts/generate'
|
13
|
+
RubiGen::Base.reset_sources
|
14
|
+
RubiGen::Base.append_sources(RubiGen::PathSource.new(:application, File.join(File.dirname(__FILE__), "../app_generators")))
|
15
|
+
RubiGen::Scripts::Generate.new.run(ARGV, :generator => 'reactive')
|
data/lib/reactive-dev.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
class CodeStatistics #:nodoc:
|
2
|
+
|
3
|
+
TEST_TYPES = %w(Units Functionals Unit\ tests Functional\ tests Integration\ tests)
|
4
|
+
|
5
|
+
def initialize(*pairs)
|
6
|
+
@pairs = pairs
|
7
|
+
@statistics = calculate_statistics
|
8
|
+
@total = calculate_total if pairs.length > 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
print_header
|
13
|
+
@pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
|
14
|
+
print_splitter
|
15
|
+
|
16
|
+
if @total
|
17
|
+
print_line("Total", @total)
|
18
|
+
print_splitter
|
19
|
+
end
|
20
|
+
|
21
|
+
print_code_test_stats
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def calculate_statistics
|
26
|
+
@pairs.inject({}) { |stats, pair| stats[pair.first] = calculate_directory_statistics(pair.last); stats }
|
27
|
+
end
|
28
|
+
|
29
|
+
def calculate_directory_statistics(directory, pattern = /.*\.rb$/)
|
30
|
+
stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
|
31
|
+
|
32
|
+
Dir.foreach(directory) do |file_name|
|
33
|
+
if File.stat(directory + "/" + file_name).directory? and (/^\./ !~ file_name)
|
34
|
+
newstats = calculate_directory_statistics(directory + "/" + file_name, pattern)
|
35
|
+
stats.each { |k, v| stats[k] += newstats[k] }
|
36
|
+
end
|
37
|
+
|
38
|
+
next unless file_name =~ pattern
|
39
|
+
|
40
|
+
f = File.open(directory + "/" + file_name)
|
41
|
+
|
42
|
+
while line = f.gets
|
43
|
+
stats["lines"] += 1
|
44
|
+
stats["classes"] += 1 if line =~ /class [A-Z]/
|
45
|
+
stats["methods"] += 1 if line =~ /def [a-z]/
|
46
|
+
stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
stats
|
51
|
+
end
|
52
|
+
|
53
|
+
def calculate_total
|
54
|
+
total = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
|
55
|
+
@statistics.each_value { |pair| pair.each { |k, v| total[k] += v } }
|
56
|
+
total
|
57
|
+
end
|
58
|
+
|
59
|
+
def calculate_code
|
60
|
+
code_loc = 0
|
61
|
+
@statistics.each { |k, v| code_loc += v['codelines'] unless TEST_TYPES.include? k }
|
62
|
+
code_loc
|
63
|
+
end
|
64
|
+
|
65
|
+
def calculate_tests
|
66
|
+
test_loc = 0
|
67
|
+
@statistics.each { |k, v| test_loc += v['codelines'] if TEST_TYPES.include? k }
|
68
|
+
test_loc
|
69
|
+
end
|
70
|
+
|
71
|
+
def print_header
|
72
|
+
print_splitter
|
73
|
+
puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |"
|
74
|
+
print_splitter
|
75
|
+
end
|
76
|
+
|
77
|
+
def print_splitter
|
78
|
+
puts "+----------------------+-------+-------+---------+---------+-----+-------+"
|
79
|
+
end
|
80
|
+
|
81
|
+
def print_line(name, statistics)
|
82
|
+
m_over_c = (statistics["methods"] / statistics["classes"]) rescue m_over_c = 0
|
83
|
+
loc_over_m = (statistics["codelines"] / statistics["methods"]) - 2 rescue loc_over_m = 0
|
84
|
+
|
85
|
+
start = if TEST_TYPES.include? name
|
86
|
+
"| #{name.ljust(20)} "
|
87
|
+
else
|
88
|
+
"| #{name.ljust(20)} "
|
89
|
+
end
|
90
|
+
|
91
|
+
puts start +
|
92
|
+
"| #{statistics["lines"].to_s.rjust(5)} " +
|
93
|
+
"| #{statistics["codelines"].to_s.rjust(5)} " +
|
94
|
+
"| #{statistics["classes"].to_s.rjust(7)} " +
|
95
|
+
"| #{statistics["methods"].to_s.rjust(7)} " +
|
96
|
+
"| #{m_over_c.to_s.rjust(3)} " +
|
97
|
+
"| #{loc_over_m.to_s.rjust(5)} |"
|
98
|
+
end
|
99
|
+
|
100
|
+
def print_code_test_stats
|
101
|
+
code = calculate_code
|
102
|
+
tests = calculate_tests
|
103
|
+
|
104
|
+
puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f/code)}"
|
105
|
+
puts ""
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Reactive
|
4
|
+
class GeneratedAttribute # :nodoc:
|
5
|
+
attr_accessor :name, :type, :column
|
6
|
+
|
7
|
+
def initialize(name, type)
|
8
|
+
@name, @type = name, type.to_sym
|
9
|
+
@column = ActiveRecord::ConnectionAdapters::Column.new(name, nil, @type)
|
10
|
+
end
|
11
|
+
|
12
|
+
def field_type
|
13
|
+
@field_type ||= case type
|
14
|
+
when :integer, :float, :decimal then :text_field
|
15
|
+
when :datetime, :timestamp, :time then :datetime_select
|
16
|
+
when :date then :date_select
|
17
|
+
when :string then :text_field
|
18
|
+
when :text then :text_area
|
19
|
+
when :boolean then :check_box
|
20
|
+
else
|
21
|
+
:text_field
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def default
|
26
|
+
@default ||= case type
|
27
|
+
when :integer then 1
|
28
|
+
when :float then 1.5
|
29
|
+
when :decimal then "9.99"
|
30
|
+
when :datetime, :timestamp, :time then Time.now.to_s(:db)
|
31
|
+
when :date then Date.today.to_s(:db)
|
32
|
+
when :string then "MyString"
|
33
|
+
when :text then "MyText"
|
34
|
+
when :boolean then false
|
35
|
+
else
|
36
|
+
""
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Reactive
|
2
|
+
# The base generator for named components: models, controllers, etc.
|
3
|
+
# The target name is taken as the first argument and inflected to
|
4
|
+
# several forms, see the attributes below..
|
5
|
+
#
|
6
|
+
# If no name is provided, the generator raises a usage error with content
|
7
|
+
# optionally read from the USAGE file in the generator's base path.
|
8
|
+
#
|
9
|
+
# For example, the +controller+ generator takes the first argument as
|
10
|
+
# the name of the class and subsequent arguments as the names of
|
11
|
+
# actions to be generated:
|
12
|
+
#
|
13
|
+
# ./script/generate controller Article index new create
|
14
|
+
#
|
15
|
+
class NamedBaseGenerator < RubiGen::Base
|
16
|
+
attr_reader :name, :underscore_name, :singular_name, :plural_name, :class_name, :singular_class_name, :plural_class_name
|
17
|
+
|
18
|
+
# these are arrays containing parts (path parts and module parts respectively)
|
19
|
+
attr_reader :path, :class_nesting
|
20
|
+
|
21
|
+
# complete pathname
|
22
|
+
attr_reader :pathname
|
23
|
+
|
24
|
+
def initialize(runtime_args, runtime_options = {})
|
25
|
+
super
|
26
|
+
|
27
|
+
# Name argument is required.
|
28
|
+
usage if runtime_args.empty?
|
29
|
+
|
30
|
+
@args = runtime_args.dup
|
31
|
+
assign_names!(@args.shift)
|
32
|
+
|
33
|
+
self.class.use_plugin_sources! [:reactive, :test_unit]
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
# Override with your own usage banner.
|
38
|
+
def banner
|
39
|
+
"Usage: #{$0} #{spec.name} #{spec.name.camelize}Name [options]"
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def assign_names!(name)
|
44
|
+
@name, @underscore_name = name, name.underscore
|
45
|
+
base_name, @path, @pathname, @class_nesting = extract_modules(@name)
|
46
|
+
@class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
|
47
|
+
if @class_nesting.empty?
|
48
|
+
@class_name = @class_name_without_nesting
|
49
|
+
@singular_class_name = @class_name_without_nesting.singularize
|
50
|
+
@plural_class_name = @class_name_without_nesting.pluralize
|
51
|
+
else
|
52
|
+
@class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
|
53
|
+
@singular_class_name = "#{@class_nesting}::#{@class_name_without_nesting.singularize}"
|
54
|
+
@plural_class_name = "#{@class_nesting}::#{@class_name_without_nesting.pluralize}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Extract modules from filesystem-style or ruby-style path:
|
59
|
+
# good/fun/stuff
|
60
|
+
# Good::Fun::Stuff
|
61
|
+
# produce the same results.
|
62
|
+
def extract_modules(name)
|
63
|
+
modules = name.include?('/') ? name.split('/') : name.split('::')
|
64
|
+
name = modules.pop
|
65
|
+
path = modules.map { |m| m.underscore }
|
66
|
+
file_path = (path + [name.underscore]).join('/')
|
67
|
+
nesting = modules.map { |m| m.camelize }.join('::')
|
68
|
+
[name, path, file_path, nesting]
|
69
|
+
end
|
70
|
+
|
71
|
+
def inflect_names(name)
|
72
|
+
camel = name.camelize
|
73
|
+
singular = camel.underscore.singularize
|
74
|
+
plural = singular.pluralize
|
75
|
+
[camel, singular, plural]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|