ritsu 0.1.0
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.
- data/README.md +96 -0
- data/Thorfile +95 -0
- data/VERSION +1 -0
- data/bin/ritsu +32 -0
- data/lib/ritsu/block.rb +259 -0
- data/lib/ritsu/ext/test_case.rb +20 -0
- data/lib/ritsu/external_library.rb +47 -0
- data/lib/ritsu/project.rb +89 -0
- data/lib/ritsu/project_generator.rb +34 -0
- data/lib/ritsu/project_generators/default_generator.rb +73 -0
- data/lib/ritsu/project_generators/default_generator_files/Thorfile.erb +9 -0
- data/lib/ritsu/project_generators/default_generator_files/meta/project.rb.erb +9 -0
- data/lib/ritsu/project_generators.rb +1 -0
- data/lib/ritsu/src_file.rb +76 -0
- data/lib/ritsu/src_files/cpp_file.rb +33 -0
- data/lib/ritsu/src_files/cpp_file_mixin.rb +13 -0
- data/lib/ritsu/src_files/executable_cmake_lists.rb +40 -0
- data/lib/ritsu/src_files/header_file.rb +46 -0
- data/lib/ritsu/src_files/header_file_mixin.rb +20 -0
- data/lib/ritsu/src_files/project_cmake_lists.rb +110 -0
- data/lib/ritsu/src_files/project_config_header_file.rb +15 -0
- data/lib/ritsu/src_files/project_config_header_template_file.rb +46 -0
- data/lib/ritsu/src_files/shared_library_cmake_lists.rb +40 -0
- data/lib/ritsu/src_files/static_library_cmake_lists.rb +40 -0
- data/lib/ritsu/src_files/target_cmake_lists.rb +159 -0
- data/lib/ritsu/src_files/templated_src_file.rb +44 -0
- data/lib/ritsu/src_files.rb +14 -0
- data/lib/ritsu/target.rb +134 -0
- data/lib/ritsu/targets/executable.rb +45 -0
- data/lib/ritsu/targets/library.rb +29 -0
- data/lib/ritsu/targets/shared_library.rb +39 -0
- data/lib/ritsu/targets/static_library.rb +33 -0
- data/lib/ritsu/targets.rb +4 -0
- data/lib/ritsu/template.rb +69 -0
- data/lib/ritsu/template_policies.rb +133 -0
- data/lib/ritsu/test_helpers.rb +124 -0
- data/lib/ritsu/thors/default_thor.rb +57 -0
- data/lib/ritsu/thors.rb +1 -0
- data/lib/ritsu/utility/accessors.rb +30 -0
- data/lib/ritsu/utility/check_upon_add_set.rb +35 -0
- data/lib/ritsu/utility/file_robot.rb +129 -0
- data/lib/ritsu/utility/files.rb +13 -0
- data/lib/ritsu/utility/instance_dependencies.rb +113 -0
- data/lib/ritsu/utility/instance_set.rb +29 -0
- data/lib/ritsu/utility/platform.rb +21 -0
- data/lib/ritsu/utility/simple_io.rb +65 -0
- data/lib/ritsu/utility/single_instance.rb +34 -0
- data/lib/ritsu/utility/strings.rb +41 -0
- data/lib/ritsu/utility.rb +8 -0
- data/lib/ritsu.rb +17 -0
- data/test/ritsu/block_test.rb +197 -0
- data/test/ritsu/external_library_test.rb +42 -0
- data/test/ritsu/project_generators/default_generator_test.rb +34 -0
- data/test/ritsu/project_test.rb +128 -0
- data/test/ritsu/src_file_test.rb +70 -0
- data/test/ritsu/src_files/cpp_file_test.rb +43 -0
- data/test/ritsu/src_files/executable_cmake_lists_test.rb +52 -0
- data/test/ritsu/src_files/header_file_test.rb +58 -0
- data/test/ritsu/src_files/project_cmake_lists_test.rb +152 -0
- data/test/ritsu/src_files/shared_library_cmake_lists_test.rb +52 -0
- data/test/ritsu/src_files/static_library_cmake_lists_test.rb +52 -0
- data/test/ritsu/src_files/target_cmake_lists_test.rb +16 -0
- data/test/ritsu/target_test.rb +106 -0
- data/test/ritsu/targets/executable_test.rb +11 -0
- data/test/ritsu/targets/shared_library_test.rb +11 -0
- data/test/ritsu/targets/static_library_test.rb +11 -0
- data/test/ritsu/template_policies_test.rb +0 -0
- data/test/ritsu/utility/accessors_test.rb +15 -0
- data/test/ritsu/utility/check_upon_add_set_test.rb +32 -0
- data/test/ritsu/utility/file_robot_test.rb +176 -0
- data/test/ritsu/utility/strings_test.rb +29 -0
- data/test/test_helpers.rb +4 -0
- metadata +209 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/template'
|
2
|
+
|
3
|
+
module Ritsu::TemplatePolicies
|
4
|
+
module StrictBlockMatchingButLeaveUserTextBe
|
5
|
+
def update_block(block, options={})
|
6
|
+
child_blocks = block.child_blocks
|
7
|
+
index = 0
|
8
|
+
child_templates.each do |child_template|
|
9
|
+
while index < child_blocks.length && child_blocks[index].id != child_template.id
|
10
|
+
index += 1
|
11
|
+
end
|
12
|
+
if index >= child_blocks.length
|
13
|
+
if child_blocks.select {|x| x.id == child_template.id}
|
14
|
+
raise ArgumentError.new("block with id '#{child_template.id}' appears out of order")
|
15
|
+
else
|
16
|
+
raise ArgumentError.new("cannot find block with id '#{child_template.id}'")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
child_template.update_block(child_blocks[index])
|
20
|
+
index += 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Blank
|
26
|
+
def update_block(block, options={})
|
27
|
+
block.contents.clear
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module DoNotUpdate
|
32
|
+
def update_block(block, options={})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Overwrite
|
37
|
+
def overwrite_block(block, options={})
|
38
|
+
block.clear_contents
|
39
|
+
contents.each do |content|
|
40
|
+
if !content.kind_of?(Ritsu::Template)
|
41
|
+
block.add_content content
|
42
|
+
else
|
43
|
+
block.add_content(content.create_block(options))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def update_block(block, options={})
|
49
|
+
overwrite_block(block, options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module FlexibleBlockMatching
|
54
|
+
##
|
55
|
+
# @param (Block) a block
|
56
|
+
# @return (Hash) a hash mapping each child template to a child block with the same id.
|
57
|
+
# If there is no such child block, the child template is mapped to nil.
|
58
|
+
def match_child_blocks(block)
|
59
|
+
child_blocks = block.child_blocks
|
60
|
+
matching_child_blocks = {}
|
61
|
+
child_templates.each do |child_template|
|
62
|
+
matching = nil
|
63
|
+
child_blocks.each do |child_block|
|
64
|
+
if child_template.id == child_block.id
|
65
|
+
matching = child_block
|
66
|
+
break
|
67
|
+
end
|
68
|
+
end
|
69
|
+
child_blocks.delete(matching) unless matching.nil?
|
70
|
+
matching_child_blocks[child_template] = matching
|
71
|
+
end
|
72
|
+
matching_child_blocks
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module FlexibleBlockMatchingAndCreateMissingBlocksButIgnoreUserText
|
77
|
+
include FlexibleBlockMatching
|
78
|
+
|
79
|
+
def update_block(block, options={})
|
80
|
+
matching_child_blocks = match_child_blocks(block)
|
81
|
+
|
82
|
+
block.contents.clear
|
83
|
+
contents.each do |content|
|
84
|
+
if content.kind_of?(Template)
|
85
|
+
if matching_child_blocks[content].nil?
|
86
|
+
block.contents << content.create_block(options)
|
87
|
+
else
|
88
|
+
matching = matching_child_blocks[content]
|
89
|
+
content.update_block(matching)
|
90
|
+
block.contents << matching
|
91
|
+
end
|
92
|
+
else
|
93
|
+
block.contents << content
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
module FlexibleBlockMatchingAndCreateMissingBlockButLeaveUserTextBe
|
100
|
+
include FlexibleBlockMatching
|
101
|
+
|
102
|
+
def update_block(block, options={})
|
103
|
+
options = {:new_line_after_block => true}.merge(options)
|
104
|
+
matching_child_blocks = match_child_blocks(block)
|
105
|
+
|
106
|
+
child_templates.each do |child_template|
|
107
|
+
if matching_child_blocks[child_template].nil?
|
108
|
+
new_block = child_template.create_block(options)
|
109
|
+
|
110
|
+
position = position_to_insert(block, new_block)
|
111
|
+
if position
|
112
|
+
block.contents.insert(position, new_block)
|
113
|
+
if options[:new_line_after_block]
|
114
|
+
block.contents.insert(position+1, "")
|
115
|
+
end
|
116
|
+
else
|
117
|
+
raise ArgumentError.new("cannot find position to insert '#{new_block.name}'")
|
118
|
+
end
|
119
|
+
else
|
120
|
+
matching = matching_child_blocks[child_template]
|
121
|
+
child_template.update_block(matching)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# @return (Integer) the position in block.contents to
|
128
|
+
# insert the given new block
|
129
|
+
def position_to_insert(block, new_block)
|
130
|
+
raise NotImplmentedError
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + "/target"
|
3
|
+
require File.dirname(__FILE__) + "/src_file"
|
4
|
+
require File.dirname(__FILE__) + "/external_library"
|
5
|
+
require File.dirname(__FILE__) + "/project"
|
6
|
+
|
7
|
+
module Ritsu
|
8
|
+
module SetupProjectAndClearEverythingElse
|
9
|
+
def setup_project(name='project')
|
10
|
+
Ritsu::Target.instances.clear
|
11
|
+
Ritsu::SrcFile.instances.clear
|
12
|
+
Ritsu::ExternalLibrary.instances.clear
|
13
|
+
@project = Ritsu::Project.create(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup
|
17
|
+
setup_project
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module TestCaseWithFileTestData
|
22
|
+
module ClassMethods
|
23
|
+
def file_test(name, &block)
|
24
|
+
case_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
25
|
+
if !Ritsu::Utility::Strings::is_c_name?(case_name.to_s)
|
26
|
+
raise "'#{name}' does not yield a valid test case name (i.e., a C name)"
|
27
|
+
end
|
28
|
+
defined = instance_method(case_name) rescue false
|
29
|
+
raise "#{case_name} is already defined in #{self}" if defined
|
30
|
+
if block_given?
|
31
|
+
define_method(case_name) do
|
32
|
+
init_data_dir
|
33
|
+
instance_eval(&block)
|
34
|
+
end
|
35
|
+
else
|
36
|
+
define_method(case_name) do
|
37
|
+
flunk "No implmentation provided for #{case_name}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.included(base)
|
44
|
+
base.extend(ClassMethods)
|
45
|
+
end
|
46
|
+
|
47
|
+
def init_data_dir
|
48
|
+
FileUtils.mkdir_p(data_dir)
|
49
|
+
FileUtils.mkdir_p(static_dir)
|
50
|
+
FileUtils.mkdir_p(output_dir)
|
51
|
+
FileUtils.rm_r(Dir.glob(output_dir + '/*'), :force=>true)
|
52
|
+
end
|
53
|
+
|
54
|
+
def data_dir
|
55
|
+
raise NotImplementedError.new
|
56
|
+
end
|
57
|
+
|
58
|
+
def data_path(path)
|
59
|
+
data_dir + '/' + path
|
60
|
+
end
|
61
|
+
|
62
|
+
def output_dir
|
63
|
+
data_dir + '/output'
|
64
|
+
end
|
65
|
+
|
66
|
+
def output_path(path)
|
67
|
+
output_dir + '/' + path
|
68
|
+
end
|
69
|
+
|
70
|
+
def static_dir
|
71
|
+
data_dir + '/static'
|
72
|
+
end
|
73
|
+
|
74
|
+
def static_path(path)
|
75
|
+
static_dir + '/' + path
|
76
|
+
end
|
77
|
+
|
78
|
+
def assert_file_exists(filename)
|
79
|
+
assert_block "#{filename} must exists" do
|
80
|
+
File.exists?(filename)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def assert_file_not_exist(filename)
|
85
|
+
assert_block "#{filename} must not exist" do
|
86
|
+
!File.exists?(filename)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def assert_data_file_exists(filename)
|
91
|
+
assert_file_exists(data_path(filename))
|
92
|
+
end
|
93
|
+
|
94
|
+
def assert_data_file_not_exist(filename)
|
95
|
+
assert_file_not_exist(data_path(filename))
|
96
|
+
end
|
97
|
+
|
98
|
+
def assert_output_file_exists(filename)
|
99
|
+
assert_file_exists(output_path(filename))
|
100
|
+
end
|
101
|
+
|
102
|
+
def assert_output_file_not_exist(filename)
|
103
|
+
assert_file_not_exist(output_path(filename))
|
104
|
+
end
|
105
|
+
|
106
|
+
def assert_file_content(content, filename)
|
107
|
+
assert_equal content, IO.read(filename)
|
108
|
+
"content of #{filename} differs from expected"
|
109
|
+
end
|
110
|
+
|
111
|
+
def assert_file_compare(expected_file, actual_file)
|
112
|
+
assert_equal IO.read(expected_file), IO.read(actual_file),
|
113
|
+
"content of #{actual_file} differs from #{expected_file}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def assert_output_file_compare_to_static(path)
|
117
|
+
assert_file_compare(static_path(path), output_path(path))
|
118
|
+
end
|
119
|
+
|
120
|
+
def assert_output_file_content(content, path)
|
121
|
+
assert_file_content(content, output_path(path))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require File.dirname(__FILE__) + '/../project'
|
3
|
+
require File.dirname(__FILE__) + '/../utility/platform'
|
4
|
+
|
5
|
+
module Ritsu::Thors
|
6
|
+
class DefaultThor < Thor
|
7
|
+
desc "update_src", "update all the source files"
|
8
|
+
def update_src
|
9
|
+
Ritsu::Project.instance.update
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "cmake", "run CMake"
|
13
|
+
method_option :generator, :type => :string
|
14
|
+
def cmake
|
15
|
+
prepare_cmake_generator
|
16
|
+
|
17
|
+
if !File.exists?(File.dirname(__FILE__) + "/build")
|
18
|
+
FileUtils.mkdir_p(File.dirname(__FILE__) + "/build")
|
19
|
+
end
|
20
|
+
|
21
|
+
FileUtils.chdir("build", :verbose => true)
|
22
|
+
system("cmake ../src -G\"#{@cmake_generator}\"")
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "update", "update source files and then run CMake"
|
26
|
+
method_option :generator, :type => :string
|
27
|
+
def update
|
28
|
+
prepare_cmake_generator
|
29
|
+
|
30
|
+
update_src
|
31
|
+
cmake
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def prepare_cmake_generator
|
36
|
+
if !options.has_key?(:generator)
|
37
|
+
@cmake_generator = default_cmake_generator(Ritsu::Utility.platform)
|
38
|
+
else
|
39
|
+
@cmake_generator = options[:generator]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def default_cmake_generator(platform)
|
44
|
+
platform = platform.to_sym
|
45
|
+
case platform
|
46
|
+
when :windows
|
47
|
+
"Visual Studio 9 2008"
|
48
|
+
when :mac
|
49
|
+
"Xcode"
|
50
|
+
when :unix
|
51
|
+
"Unix Makefiles"
|
52
|
+
else
|
53
|
+
raise ArgumentError.new("invalid platform '#{platform.to_s}'")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/ritsu/thors.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/thors/default_thor'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Ritsu
|
2
|
+
module Utility
|
3
|
+
module Accessors
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def attr_method_single(name)
|
10
|
+
name = name.to_s
|
11
|
+
module_eval <<-_RUBY
|
12
|
+
def #{name}(*args)
|
13
|
+
if args.length == 0
|
14
|
+
@#{name} ||= nil
|
15
|
+
elsif args.length == 1
|
16
|
+
@#{name} = args[0]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
_RUBY
|
20
|
+
end
|
21
|
+
|
22
|
+
def attr_method(*names)
|
23
|
+
names.each do |name|
|
24
|
+
attr_method_single(name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Ritsu
|
4
|
+
module Utility
|
5
|
+
class CheckUponAddSet < Set
|
6
|
+
def initialize(*args, &block)
|
7
|
+
if block_given?
|
8
|
+
@check_block = block
|
9
|
+
else
|
10
|
+
@check_block = Proc.new { }
|
11
|
+
end
|
12
|
+
super(*args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def <<(x)
|
16
|
+
@check_block.call(self, x)
|
17
|
+
super(x)
|
18
|
+
end
|
19
|
+
|
20
|
+
def add(x)
|
21
|
+
@check_block.call(self, x)
|
22
|
+
super(x)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add?(x)
|
26
|
+
begin
|
27
|
+
@check_block.call(self, x)
|
28
|
+
super(x)
|
29
|
+
rescue
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'singleton'
|
3
|
+
require File.dirname(__FILE__) + '/../utility/simple_io'
|
4
|
+
|
5
|
+
module Ritsu
|
6
|
+
module Utility
|
7
|
+
class FileRobot
|
8
|
+
include Singleton
|
9
|
+
def self.v; instance end
|
10
|
+
|
11
|
+
def self.method_missing(symbol, *args, &block)
|
12
|
+
instance.send(symbol, *args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :force
|
16
|
+
attr_reader :io
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@io = SimpleIO.new
|
20
|
+
@force = false
|
21
|
+
end
|
22
|
+
|
23
|
+
def output; io.output end
|
24
|
+
def output=(value); io.output = value end
|
25
|
+
def input; io.input end
|
26
|
+
def input=(value); io.input = value end
|
27
|
+
def quiet; io.quiet end
|
28
|
+
def quiet=(value); io.quiet = value end
|
29
|
+
|
30
|
+
def quietly(&block)
|
31
|
+
old_quiet = self.quiet
|
32
|
+
self.quiet = true
|
33
|
+
block.call
|
34
|
+
self.quiet = old_quiet
|
35
|
+
end
|
36
|
+
|
37
|
+
def verbosely(&block)
|
38
|
+
old_quiet = self.quiet
|
39
|
+
self.quiet = false
|
40
|
+
block.call
|
41
|
+
self.quiet = old_quiet
|
42
|
+
end
|
43
|
+
|
44
|
+
def forcefully(&block)
|
45
|
+
old_force = self.force
|
46
|
+
self.force = true
|
47
|
+
block.call
|
48
|
+
self.force = old_force
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_dir(dir_name, options={})
|
52
|
+
options = {:echo_exists=>true}.merge(options)
|
53
|
+
if File.exists?(dir_name)
|
54
|
+
if options[:echo_exists]
|
55
|
+
io.log('exist', dir_name)
|
56
|
+
end
|
57
|
+
else
|
58
|
+
FileUtils.mkdir_p(dir_name)
|
59
|
+
io.log('create', dir_name)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_file(filename, content="")
|
64
|
+
do_create_file = Proc.new do
|
65
|
+
File.open(filename, "w") { |f| f.write content }
|
66
|
+
end
|
67
|
+
|
68
|
+
do_overwrite = Proc.new do
|
69
|
+
do_create_file.call
|
70
|
+
io.log('overwrite', filename)
|
71
|
+
end
|
72
|
+
|
73
|
+
create_dir(File.dirname(filename), :echo_exists=>false)
|
74
|
+
if File.exists?(filename)
|
75
|
+
if force
|
76
|
+
do_overwrite.call
|
77
|
+
else
|
78
|
+
answer = io.ask_yes_no_all("overwrite #{filename}?")
|
79
|
+
case answer
|
80
|
+
when :yes
|
81
|
+
do_overwrite.call
|
82
|
+
when :no
|
83
|
+
io.log('exist', filename)
|
84
|
+
when :all
|
85
|
+
force = true
|
86
|
+
do_overwrite.call
|
87
|
+
end
|
88
|
+
end
|
89
|
+
else
|
90
|
+
do_create_file.call
|
91
|
+
io.log('create', filename)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def remove_dir(dirname)
|
96
|
+
if !File.exist?(dirname)
|
97
|
+
io.log("not exist", dirname)
|
98
|
+
elsif !File.directory?(dirname)
|
99
|
+
io.log("not dir", dirname)
|
100
|
+
else
|
101
|
+
begin
|
102
|
+
Dir.glob(dirname + "/*") { throw "not empty" }
|
103
|
+
is_empty = true
|
104
|
+
rescue
|
105
|
+
is_empty = false
|
106
|
+
end
|
107
|
+
|
108
|
+
if !is_empty
|
109
|
+
io.log('not empty', dirname)
|
110
|
+
elsif
|
111
|
+
FileUtils.remove_dir(dirname)
|
112
|
+
io.log("remove", dirname)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def remove_file(filename)
|
118
|
+
if !File.exists?(filename)
|
119
|
+
io.log("not exist", filename)
|
120
|
+
elsif !File.file?(filename)
|
121
|
+
io.log("not file", filename)
|
122
|
+
else
|
123
|
+
FileUtils.remove_file(filename)
|
124
|
+
io.log("remove", filename)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support/core_ext/string/inflections'
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require File.dirname(__FILE__) + "/instance_set"
|
5
|
+
|
6
|
+
module Ritsu
|
7
|
+
module Utility
|
8
|
+
module InstanceDependencies
|
9
|
+
def self.included(base)
|
10
|
+
base.extend(ClassMethods)
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def dependencies_between(name)
|
15
|
+
name = name.to_s.singularize
|
16
|
+
dependency_set_name = "dependency_#{name.pluralize}"
|
17
|
+
|
18
|
+
module_eval <<-RUBY
|
19
|
+
attr_reader :#{dependency_set_name}
|
20
|
+
attr_accessor :topological_order
|
21
|
+
|
22
|
+
def #{dependency_set_name}
|
23
|
+
@#{dependency_set_name} ||= Ritsu::Utility::CheckUponAddSet.new do |s,dependency|
|
24
|
+
validate_dependency_#{name}(dependency)
|
25
|
+
self.class.invalidate_topological_orders
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def depends_directly_on_#{name}?(instance)
|
30
|
+
#{dependency_set_name}.include?(instance)
|
31
|
+
end
|
32
|
+
|
33
|
+
def depends_on_#{name}?(instance)
|
34
|
+
visited = Set.new [self]
|
35
|
+
queue = [self]
|
36
|
+
|
37
|
+
# Perform a breadth first search
|
38
|
+
while !visited.include?(instance) && !queue.empty?
|
39
|
+
u = queue.shift
|
40
|
+
u.#{dependency_set_name}.each do |v|
|
41
|
+
if !visited.include?(v)
|
42
|
+
queue << v
|
43
|
+
visited << v
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
visited.delete(self)
|
49
|
+
visited.include?(instance)
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate_dependency_#{name}(instance)
|
53
|
+
instance_name = instance.name
|
54
|
+
if instance == self
|
55
|
+
raise ArgumentError.new("'\#{instance.name}' is the same as the dependent #{name}")
|
56
|
+
end
|
57
|
+
if instance.depends_on_#{name}?(self)
|
58
|
+
raise ArgumentError.new("including '\#{instance.name}' will create a circular dependency")
|
59
|
+
end
|
60
|
+
if !instance.can_be_depended_on?
|
61
|
+
raise ArgumentError.new("'\#{instance.name}' cannot be dependend on")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.recompute_topological_orders
|
66
|
+
indegrees = {}
|
67
|
+
instances.each { |instance| indegrees[instance] = 0 }
|
68
|
+
instances.each do |instance|
|
69
|
+
instance.#{dependency_set_name}.each do |dependency|
|
70
|
+
indegrees[dependency] += 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
last_order = instances.length-1
|
75
|
+
indegree_zero = instances.select { |instance| indegrees[instance] == 0 }
|
76
|
+
while !indegree_zero.empty?
|
77
|
+
u = indegree_zero.shift
|
78
|
+
u.topological_order = last_order
|
79
|
+
last_order -= 1
|
80
|
+
u.#{dependency_set_name}.each do |v|
|
81
|
+
indegrees[v] -= 1
|
82
|
+
if indegrees[v] == 0
|
83
|
+
indegree_zero << v
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
@topological_orders_computed = true
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.topological_orders_computed?
|
92
|
+
@topological_order_computed ||= false
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.compute_topological_orders
|
96
|
+
if !topological_orders_computed?
|
97
|
+
recompute_topological_orders
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.invalidate_topological_orders
|
102
|
+
@topological_order_computed = false
|
103
|
+
end
|
104
|
+
|
105
|
+
def can_be_depended_on?
|
106
|
+
raise NotImplementedError.new
|
107
|
+
end
|
108
|
+
RUBY
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../utility/check_upon_add_set'
|
2
|
+
|
3
|
+
module Ritsu
|
4
|
+
module Utility
|
5
|
+
module InstanceSet
|
6
|
+
module ClassMethods
|
7
|
+
def instances
|
8
|
+
@instances ||= Ritsu::Utility::CheckUponAddSet.new do |s, instance|
|
9
|
+
validate_instance(instance)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate_instance(instance)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.extend(ClassMethods)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(*args, &block)
|
22
|
+
self.class.instances << self
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize_instance(*args, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Ritsu
|
2
|
+
module Utility
|
3
|
+
def platform
|
4
|
+
case RUBY_PLATFORM.downcase
|
5
|
+
when /linux|bsd|solaris|hpux/
|
6
|
+
:unix
|
7
|
+
when /darwin/
|
8
|
+
:mac
|
9
|
+
when /mswin32|mingw32|bccwin32/
|
10
|
+
:windows
|
11
|
+
when /cygwin/
|
12
|
+
:cygwin
|
13
|
+
when /java/
|
14
|
+
:java
|
15
|
+
else
|
16
|
+
:other
|
17
|
+
end
|
18
|
+
end
|
19
|
+
module_function :platform
|
20
|
+
end
|
21
|
+
end
|