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.
Files changed (73) hide show
  1. data/README.md +96 -0
  2. data/Thorfile +95 -0
  3. data/VERSION +1 -0
  4. data/bin/ritsu +32 -0
  5. data/lib/ritsu/block.rb +259 -0
  6. data/lib/ritsu/ext/test_case.rb +20 -0
  7. data/lib/ritsu/external_library.rb +47 -0
  8. data/lib/ritsu/project.rb +89 -0
  9. data/lib/ritsu/project_generator.rb +34 -0
  10. data/lib/ritsu/project_generators/default_generator.rb +73 -0
  11. data/lib/ritsu/project_generators/default_generator_files/Thorfile.erb +9 -0
  12. data/lib/ritsu/project_generators/default_generator_files/meta/project.rb.erb +9 -0
  13. data/lib/ritsu/project_generators.rb +1 -0
  14. data/lib/ritsu/src_file.rb +76 -0
  15. data/lib/ritsu/src_files/cpp_file.rb +33 -0
  16. data/lib/ritsu/src_files/cpp_file_mixin.rb +13 -0
  17. data/lib/ritsu/src_files/executable_cmake_lists.rb +40 -0
  18. data/lib/ritsu/src_files/header_file.rb +46 -0
  19. data/lib/ritsu/src_files/header_file_mixin.rb +20 -0
  20. data/lib/ritsu/src_files/project_cmake_lists.rb +110 -0
  21. data/lib/ritsu/src_files/project_config_header_file.rb +15 -0
  22. data/lib/ritsu/src_files/project_config_header_template_file.rb +46 -0
  23. data/lib/ritsu/src_files/shared_library_cmake_lists.rb +40 -0
  24. data/lib/ritsu/src_files/static_library_cmake_lists.rb +40 -0
  25. data/lib/ritsu/src_files/target_cmake_lists.rb +159 -0
  26. data/lib/ritsu/src_files/templated_src_file.rb +44 -0
  27. data/lib/ritsu/src_files.rb +14 -0
  28. data/lib/ritsu/target.rb +134 -0
  29. data/lib/ritsu/targets/executable.rb +45 -0
  30. data/lib/ritsu/targets/library.rb +29 -0
  31. data/lib/ritsu/targets/shared_library.rb +39 -0
  32. data/lib/ritsu/targets/static_library.rb +33 -0
  33. data/lib/ritsu/targets.rb +4 -0
  34. data/lib/ritsu/template.rb +69 -0
  35. data/lib/ritsu/template_policies.rb +133 -0
  36. data/lib/ritsu/test_helpers.rb +124 -0
  37. data/lib/ritsu/thors/default_thor.rb +57 -0
  38. data/lib/ritsu/thors.rb +1 -0
  39. data/lib/ritsu/utility/accessors.rb +30 -0
  40. data/lib/ritsu/utility/check_upon_add_set.rb +35 -0
  41. data/lib/ritsu/utility/file_robot.rb +129 -0
  42. data/lib/ritsu/utility/files.rb +13 -0
  43. data/lib/ritsu/utility/instance_dependencies.rb +113 -0
  44. data/lib/ritsu/utility/instance_set.rb +29 -0
  45. data/lib/ritsu/utility/platform.rb +21 -0
  46. data/lib/ritsu/utility/simple_io.rb +65 -0
  47. data/lib/ritsu/utility/single_instance.rb +34 -0
  48. data/lib/ritsu/utility/strings.rb +41 -0
  49. data/lib/ritsu/utility.rb +8 -0
  50. data/lib/ritsu.rb +17 -0
  51. data/test/ritsu/block_test.rb +197 -0
  52. data/test/ritsu/external_library_test.rb +42 -0
  53. data/test/ritsu/project_generators/default_generator_test.rb +34 -0
  54. data/test/ritsu/project_test.rb +128 -0
  55. data/test/ritsu/src_file_test.rb +70 -0
  56. data/test/ritsu/src_files/cpp_file_test.rb +43 -0
  57. data/test/ritsu/src_files/executable_cmake_lists_test.rb +52 -0
  58. data/test/ritsu/src_files/header_file_test.rb +58 -0
  59. data/test/ritsu/src_files/project_cmake_lists_test.rb +152 -0
  60. data/test/ritsu/src_files/shared_library_cmake_lists_test.rb +52 -0
  61. data/test/ritsu/src_files/static_library_cmake_lists_test.rb +52 -0
  62. data/test/ritsu/src_files/target_cmake_lists_test.rb +16 -0
  63. data/test/ritsu/target_test.rb +106 -0
  64. data/test/ritsu/targets/executable_test.rb +11 -0
  65. data/test/ritsu/targets/shared_library_test.rb +11 -0
  66. data/test/ritsu/targets/static_library_test.rb +11 -0
  67. data/test/ritsu/template_policies_test.rb +0 -0
  68. data/test/ritsu/utility/accessors_test.rb +15 -0
  69. data/test/ritsu/utility/check_upon_add_set_test.rb +32 -0
  70. data/test/ritsu/utility/file_robot_test.rb +176 -0
  71. data/test/ritsu/utility/strings_test.rb +29 -0
  72. data/test/test_helpers.rb +4 -0
  73. 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
@@ -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,13 @@
1
+ module Ritsu
2
+ module Utility
3
+ module Files
4
+ def read(filename)
5
+ f = File.new(filename)
6
+ result = f.read
7
+ f.close
8
+ result
9
+ end
10
+ module_function :read
11
+ end
12
+ end
13
+ 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