ruby_ex 0.1.2 → 0.2.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 (122) hide show
  1. data/ChangeLog +693 -0
  2. data/NEWS +74 -0
  3. data/SPEC.dyn.yml +6 -6
  4. data/SPEC.gemspec +14 -0
  5. data/SPEC.yml +4 -4
  6. data/lib/abstract.rb +2 -4
  7. data/lib/abstract_node.rb +1 -2
  8. data/lib/algorithms/simulated_annealing.rb +50 -29
  9. data/lib/attributed_class.rb +50 -21
  10. data/lib/auto_object.rb +102 -0
  11. data/lib/blank_slate.rb +102 -0
  12. data/lib/cache.rb +1 -2
  13. data/lib/choose.rb +165 -163
  14. data/lib/commands.rb +2 -3
  15. data/lib/commands/command.rb +47 -20
  16. data/lib/commands/datas.rb +1 -1
  17. data/lib/commands/datas/composite.rb +5 -1
  18. data/lib/commands/datas/data.rb +102 -5
  19. data/lib/commands/datas/factory.rb +13 -6
  20. data/lib/commands/datas/temp.rb +3 -5
  21. data/lib/commands/factory.rb +1 -1
  22. data/lib/commands/helpers.rb +1 -1
  23. data/lib/commands/pipe.rb +10 -1
  24. data/lib/commands/runners.rb +1 -1
  25. data/lib/commands/runners/exec.rb +1 -1
  26. data/lib/commands/runners/fork.rb +3 -16
  27. data/lib/commands/runners/mock.rb +67 -0
  28. data/lib/commands/runners/runner.rb +5 -3
  29. data/lib/commands/runners/system.rb +1 -1
  30. data/lib/commands/seq.rb +2 -1
  31. data/lib/config_file.rb +10 -2
  32. data/lib/const_regexp.rb +1 -2
  33. data/lib/{dlogger.rb → d_logger.rb} +1 -2
  34. data/lib/daemon.rb +1 -2
  35. data/lib/diff.rb +1 -2
  36. data/lib/drb/drb_observable.rb +1 -2
  37. data/lib/drb/drb_observable_pool.rb +2 -2
  38. data/lib/drb/drb_service.rb +1 -2
  39. data/lib/drb/drb_undumped_attributes.rb +1 -2
  40. data/lib/drb/drb_undumped_indexed_object.rb +1 -2
  41. data/lib/drb/insecure_protected_methods.rb +1 -2
  42. data/lib/drb_ex.rb +2 -2
  43. data/lib/file_type.rb +466 -0
  44. data/lib/generate_id.rb +12 -6
  45. data/lib/genpasswd.rb +22 -0
  46. data/lib/hash_eval.rb +83 -0
  47. data/lib/histogram.rb +1 -2
  48. data/lib/hookable.rb +3 -4
  49. data/lib/hooker.rb +1 -3
  50. data/lib/html_encode.rb +191 -0
  51. data/lib/indexed_node.rb +0 -1
  52. data/lib/io_marshal.rb +4 -2
  53. data/lib/ioo.rb +3 -2
  54. data/lib/kill_all.rb +46 -0
  55. data/lib/labeled_node.rb +0 -1
  56. data/lib/logger_observer.rb +8 -4
  57. data/lib/md5sum.rb +3 -3
  58. data/lib/meta_factory.rb +99 -0
  59. data/lib/method_call.rb +87 -0
  60. data/lib/mocks.rb +12 -0
  61. data/lib/mocks/assertions.rb +50 -0
  62. data/lib/mocks/method_logger.rb +40 -0
  63. data/lib/mocks/mock.rb +64 -0
  64. data/lib/mocks/object.rb +47 -0
  65. data/lib/mocks/observer.rb +38 -0
  66. data/lib/module/autoload_tree.rb +30 -29
  67. data/lib/module/hierarchy.rb +176 -171
  68. data/lib/module/instance_method_visibility.rb +39 -38
  69. data/lib/node.rb +0 -1
  70. data/lib/object_monitor.rb +1 -2
  71. data/lib/object_monitor_activity.rb +1 -2
  72. data/lib/observable.rb +1 -2
  73. data/lib/observable_pool.rb +1 -2
  74. data/lib/{orderedhash.rb → ordered_hash.rb} +41 -5
  75. data/lib/pp_hierarchy.rb +7 -2
  76. data/lib/r_path.rb +307 -0
  77. data/lib/random_generators.rb +7 -20
  78. data/lib/random_generators/random_generator.rb +2 -4
  79. data/lib/random_generators/ruby.rb +4 -2
  80. data/lib/regex_path.rb +124 -0
  81. data/lib/ruby_ex.rb +28 -98
  82. data/lib/safe_eval.rb +1 -2
  83. data/lib/sendmail.rb +14 -17
  84. data/lib/service_manager.rb +1 -2
  85. data/lib/shuffle.rb +6 -2
  86. data/lib/spring.rb +1 -2
  87. data/lib/spring_set.rb +1 -2
  88. data/lib/{symtbl.rb → sym_tbl.rb} +90 -5
  89. data/lib/sym_tbl_gsub.rb +227 -0
  90. data/lib/{synflow.rb → syn_flow.rb} +1 -2
  91. data/lib/text.rb +218 -0
  92. data/lib/timeout_ex.rb +1 -2
  93. data/lib/trace.rb +9 -8
  94. data/lib/uri/druby.rb +1 -2
  95. data/lib/uri/file.rb +1 -1
  96. data/lib/uri/ftp_ex.rb +1 -1
  97. data/lib/uri/http_ex.rb +1 -1
  98. data/lib/uri/mysql.rb +121 -0
  99. data/lib/uri/pgsql.rb +19 -38
  100. data/lib/uri/svn.rb +1 -2
  101. data/lib/uri_ex.rb +45 -3
  102. data/lib/verbose_object.rb +181 -38
  103. data/lib/yaml/chop_header.rb +19 -11
  104. data/lib/yaml/transform.rb +17 -11
  105. data/lib/yaml/yregexpath.rb +11 -5
  106. data/test/algorithms/simulated_annealing_test.rb +2 -2
  107. data/test/resources/foo.tar.gz +0 -0
  108. data/test/resources/tar.gz.log +49 -0
  109. data/test/sanity-suite.yml +5 -7
  110. data/test/sanity/multiple-requires.yml +17 -7
  111. data/test/sanity/single-requires.yml +38 -20
  112. data/test/stress-tests/threads_and_exceptions.yml +13 -0
  113. data/test/test-unit-setup.rb +3 -1
  114. data/test/unit-suite.yml +7 -8
  115. metadata +42 -31
  116. data/lib/algorithms.rb +0 -12
  117. data/lib/ask.rb +0 -100
  118. data/lib/checkout.rb +0 -12
  119. data/lib/dumpable_proc.rb +0 -57
  120. data/lib/filetype.rb +0 -229
  121. data/lib/thread_mutex.rb +0 -11
  122. data/lib/yaml/basenode_ext.rb +0 -63
@@ -1,7 +1,7 @@
1
1
  # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
2
  # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
3
  # License:: GNU General Public License (GPL).
4
- # Revision:: $Id: helpers.rb 279 2005-06-05 17:46:53Z ertai $
4
+ # Revision:: $Id: helpers.rb 255 2005-06-01 00:08:46Z ertai $
5
5
 
6
6
  require 'commands'
7
7
 
data/lib/commands/pipe.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
2
  # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
3
  # License:: GNU General Public License (GPL).
4
- # Revision:: $Id: pipe.rb 279 2005-06-05 17:46:53Z ertai $
4
+ # Revision:: $Id: pipe.rb 341 2005-09-07 00:01:43Z ertai $
5
5
 
6
6
  require 'commands'
7
7
 
@@ -11,6 +11,7 @@ module Commands
11
11
 
12
12
  def initialize ( *cmds )
13
13
  @cmds = cmds.map { |x| x.dup }
14
+ @input, @output, @error = nil, nil, nil
14
15
  end
15
16
 
16
17
  def run ( *a )
@@ -56,6 +57,14 @@ module Commands
56
57
  @cmds.last.error
57
58
  end
58
59
 
60
+ %w[ args command ].each do |meth|
61
+ class_eval %Q{
62
+ def #{meth} ( *a, &b )
63
+ raise ArgumentError, "no method `#{meth}' on a pipe"
64
+ end
65
+ }
66
+ end
67
+
59
68
  def to_sh
60
69
  strs = @cmds.map { |cmd| "(#{cmd.to_sh})" }
61
70
  "(#{strs.join(' | ')})#{sh_args}"
@@ -1,7 +1,7 @@
1
1
  # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
2
  # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
3
  # License:: GNU General Public License (GPL).
4
- # Revision:: $Id: runners.rb 279 2005-06-05 17:46:53Z ertai $
4
+ # Revision:: $Id: runners.rb 255 2005-06-01 00:08:46Z ertai $
5
5
 
6
6
  require 'commands'
7
7
 
@@ -1,7 +1,7 @@
1
1
  # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
2
  # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
3
  # License:: GNU General Public License (GPL).
4
- # Revision:: $Id: exec.rb 279 2005-06-05 17:46:53Z ertai $
4
+ # Revision:: $Id: exec.rb 255 2005-06-01 00:08:46Z ertai $
5
5
 
6
6
  require 'commands'
7
7
 
@@ -1,7 +1,7 @@
1
1
  # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
2
  # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
3
  # License:: GNU General Public License (GPL).
4
- # Revision:: $Id: fork.rb 279 2005-06-05 17:46:53Z ertai $
4
+ # Revision:: $Id: fork.rb 358 2005-09-16 09:54:04Z ertai $
5
5
 
6
6
  require 'commands'
7
7
 
@@ -30,6 +30,7 @@ module Commands
30
30
  def run_impl ( aCommand, data )
31
31
  data.pid = Kernel.fork do
32
32
  begin
33
+ TempPath.fork_init
33
34
  hook_trigger :son, aCommand, data
34
35
  super
35
36
  rescue Exception => ex
@@ -80,21 +81,7 @@ module Commands
80
81
  class Error < Exception
81
82
  end
82
83
  def failure ( data )
83
- output, error = '', ''
84
- output = data.output.read rescue nil
85
- error = data.error.read rescue nil
86
- output.gsub!(/^/, ' ')
87
- error.gsub!(/^/, ' ')
88
-
89
- raise Error, <<end
90
- ---
91
- Command failed:
92
- exit: #{data.status.exitstatus}
93
- output:
94
- #{output}
95
- error:
96
- #{error}
97
- end
84
+ raise Error, { 'Command failed' => data }.to_yaml
98
85
  end
99
86
  end
100
87
 
@@ -0,0 +1,67 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: mock.rb 302 2005-06-23 21:03:51Z ertai $
5
+
6
+ require 'commands'
7
+
8
+ module Commands
9
+
10
+ module Runners
11
+
12
+ class Mock < Runner
13
+ concrete
14
+
15
+ attr_reader :log
16
+
17
+ def initialize ( *a, &b )
18
+ @log = []
19
+ @contents = b
20
+ super
21
+ end
22
+
23
+ def run_impl ( aCommand, data )
24
+ end
25
+
26
+ def run ( aCommand )
27
+ d = super
28
+ d.output.open('w', &@contents)
29
+ d.status = 0
30
+ d
31
+ end
32
+
33
+ def display_command ( m )
34
+ @log << m
35
+ end
36
+
37
+ end # class Mock
38
+
39
+
40
+
41
+ test_section __FILE__ do
42
+
43
+ class MockTest < Test::Unit::TestCase
44
+
45
+ def setup
46
+ assert_nothing_raised { @runner = Mock.new }
47
+ end
48
+
49
+ def test_0_initialize
50
+ end
51
+
52
+ def test_simple
53
+ assert_nothing_raised do
54
+ @cmd = 'foo bar baz'.to_cmd
55
+ @data = @runner.run(@cmd)
56
+ end
57
+ assert_kind_of(Commands::Datas::Data, @data)
58
+ assert_equal([@cmd], @runner.log)
59
+ end
60
+
61
+ end # class SystemTest
62
+
63
+ end
64
+
65
+ end # module Runners
66
+
67
+ end # module Commands
@@ -1,7 +1,7 @@
1
1
  # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
2
  # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
3
  # License:: GNU General Public License (GPL).
4
- # Revision:: $Id: runner.rb 279 2005-06-05 17:46:53Z ertai $
4
+ # Revision:: $Id: runner.rb 343 2005-09-08 01:32:57Z ertai $
5
5
 
6
6
  require 'commands'
7
7
 
@@ -11,8 +11,7 @@ module Commands
11
11
 
12
12
  class Runner
13
13
 
14
- abstract
15
-
14
+ include Abstract
16
15
  include Hookable
17
16
  include Hooker
18
17
 
@@ -42,6 +41,7 @@ module Commands
42
41
 
43
42
  def initialize
44
43
  @command_data_factory = Datas::Factory.new
44
+ @open_mode = :w
45
45
  hooker_subscribe self
46
46
  end
47
47
 
@@ -58,6 +58,7 @@ module Commands
58
58
  hook_trigger :display_command, aCommand
59
59
 
60
60
  data = @command_data_factory.create
61
+ data.open_mode = @open_mode
61
62
  data.input = aCommand.input unless aCommand.input.nil?
62
63
  data.output = aCommand.output unless aCommand.output.nil?
63
64
  data.error = aCommand.error unless aCommand.error.nil?
@@ -70,6 +71,7 @@ module Commands
70
71
 
71
72
  def run_impl ( aCommand, data )
72
73
  hook_trigger :before_open, data
74
+ aCommand = aCommand.instanciate_args
73
75
  STDIN.reopen(data.input.to_io_for_commands) unless data.input.nil?
74
76
  STDOUT.reopen(data.output.to_io_for_commands) unless data.output.nil?
75
77
  STDERR.reopen(data.error.to_io_for_commands) unless data.error.nil?
@@ -1,7 +1,7 @@
1
1
  # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
2
  # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
3
  # License:: GNU General Public License (GPL).
4
- # Revision:: $Id: system.rb 279 2005-06-05 17:46:53Z ertai $
4
+ # Revision:: $Id: system.rb 255 2005-06-01 00:08:46Z ertai $
5
5
 
6
6
  require 'commands'
7
7
 
data/lib/commands/seq.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
2
  # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
3
  # License:: GNU General Public License (GPL).
4
- # Revision:: $Id: seq.rb 279 2005-06-05 17:46:53Z ertai $
4
+ # Revision:: $Id: seq.rb 341 2005-09-07 00:01:43Z ertai $
5
5
 
6
6
  require 'commands'
7
7
 
@@ -11,6 +11,7 @@ module Commands
11
11
 
12
12
  def initialize ( *cmds )
13
13
  @cmds = cmds
14
+ @input, @output, @error = nil, nil, nil
14
15
  end
15
16
 
16
17
  def run ( *a )
data/lib/config_file.rb CHANGED
@@ -3,10 +3,9 @@
3
3
  # License: Gnu General Public License.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: config_file.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: config_file.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
8
 
9
- require 'ruby_ex'
10
9
  require 'pathname'
11
10
  require 'yaml'
12
11
  require 'delegate'
@@ -68,6 +67,15 @@ require 'tempfile'
68
67
 
69
68
  class ConfigFileTest < Test::Unit::TestCase
70
69
 
70
+ def setup
71
+ @verbose = $VERBOSE
72
+ $VERBOSE = false
73
+ end
74
+
75
+ def teardown
76
+ $VERBOSE = @verbose
77
+ end
78
+
71
79
  def test_config_file
72
80
  tmp_file = nil
73
81
  Tempfile.open('config_file') do |f|
data/lib/const_regexp.rb CHANGED
@@ -3,9 +3,8 @@
3
3
  # License: Gnu General Public License.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: const_regexp.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: const_regexp.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
- require 'ruby_ex'
9
8
 
10
9
  module ConstRegexp
11
10
 
@@ -3,9 +3,8 @@
3
3
  # License: Gnu General Public License.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: dlogger.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: d_logger.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
- require 'ruby_ex'
9
8
  require 'logger'
10
9
 
11
10
  # This Logger subclass permit to use more debug levels
data/lib/daemon.rb CHANGED
@@ -3,13 +3,12 @@
3
3
  # License: Gnu General Public License.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: daemon.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: daemon.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
8
 
9
9
  require 'pathname'
10
10
  require 'singleton'
11
11
 
12
- require 'ruby_ex'
13
12
  require 'observable'
14
13
  require 'observable_pool'
15
14
  require 'service_manager'
data/lib/diff.rb CHANGED
@@ -3,9 +3,8 @@
3
3
  # License: Gnu General Public License.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: diff.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: diff.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
- require 'ruby_ex'
9
8
 
10
9
  module Diff
11
10
 
@@ -3,10 +3,9 @@
3
3
  # License: Gnu General Public License.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: drb_observable.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: drb_observable.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
8
 
9
- require 'ruby_ex'
10
9
  require 'drb/observer'
11
10
 
12
11
  require 'observable'
@@ -2,8 +2,8 @@
2
2
  # Author: Nicolas Despres <polrop@lrde.epita.fr>.
3
3
  # License: Gnu General Public License.
4
4
 
5
- # $LastChangedBy: ertai $
6
- # $Id: drb_observable_pool.rb 279 2005-06-05 17:46:53Z ertai $
5
+ # $LastChangedBy: polrop $
6
+ # $Id: drb_observable_pool.rb 97 2005-01-13 18:20:49Z polrop $
7
7
 
8
8
 
9
9
  require 'observable_pool'
@@ -3,10 +3,9 @@
3
3
  # License:: Ruby license.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: drb_service.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: drb_service.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
8
 
9
- require 'ruby_ex'
10
9
  require 'drb/drb'
11
10
 
12
11
 
@@ -3,10 +3,9 @@
3
3
  # License: Gnu General Public License.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: drb_undumped_attributes.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: drb_undumped_attributes.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
8
 
9
- require 'ruby_ex'
10
9
  require 'drb/drb'
11
10
 
12
11
 
@@ -3,10 +3,9 @@
3
3
  # License:: Ruby license.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: drb_undumped_indexed_object.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: drb_undumped_indexed_object.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
8
 
9
- require 'ruby_ex'
10
9
  require 'drb'
11
10
 
12
11
 
@@ -3,10 +3,9 @@
3
3
  # License: Gnu General Public License.
4
4
 
5
5
  # $LastChangedBy: ertai $
6
- # $Id: insecure_protected_methods.rb 279 2005-06-05 17:46:53Z ertai $
6
+ # $Id: insecure_protected_methods.rb 339 2005-09-06 23:27:27Z ertai $
7
7
 
8
8
 
9
- require 'ruby_ex'
10
9
  require 'drb/drb'
11
10
 
12
11
 
data/lib/drb_ex.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
2
2
  # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
3
3
  # License:: Gnu General Public License.
4
- # Revision:: $Id: drb_ex.rb 279 2005-06-05 17:46:53Z ertai $
4
+ # Revision:: $Id: drb_ex.rb 344 2005-09-08 01:44:18Z ertai $
5
5
 
6
- require 'module/autoload_tree'
6
+ AutoloadTree.import!
7
7
 
8
8
  module DRb
9
9
 
data/lib/file_type.rb ADDED
@@ -0,0 +1,466 @@
1
+ require 'abstract'
2
+ require 'commands'
3
+ require 'active_support/class_attribute_accessors'
4
+ require 'active_support/class_inheritable_attributes'
5
+
6
+ module FileType
7
+
8
+ @@subclasses = []
9
+
10
+ def self.register ( klass )
11
+ @@subclasses << klass
12
+ end
13
+
14
+
15
+ GZIP = 'gzip'.to_cmd
16
+ BZIP2 = 'bzip2'.to_cmd
17
+ UNZIP = 'unzip'.to_cmd
18
+ TAR = 'tar'.to_cmd
19
+ GEM = 'gem'.to_cmd
20
+
21
+
22
+ class Generic
23
+ abstract
24
+
25
+ attr_reader :path, :base, :ext
26
+
27
+ def initialize ( path )
28
+ @path = Pathname.new(path)
29
+ re = self.class.extension
30
+ raise ArgumentError, "bad class #{self.class}" if re.nil?
31
+ unless @path.to_s =~ re
32
+ raise ArgumentError, "#{@path} do not match /#{re.source}/"
33
+ end
34
+ @base, @ext = $`, $&
35
+ if @ext.empty?
36
+ @base = self
37
+ else
38
+ @base = FileType.guess(@base)
39
+ end
40
+ end
41
+
42
+ def extsplit
43
+ [@base, @ext]
44
+ end
45
+
46
+ def self.inherited ( klass )
47
+ FileType.register(klass)
48
+ super
49
+ end
50
+
51
+ def to_s
52
+ @path.to_s
53
+ end
54
+
55
+ def self.match_type ( path, max, best )
56
+ ext_re = self.extension
57
+ if path.to_s =~ ext_re
58
+ cur = $&.size * self.priority
59
+ return [cur, self] if cur > max
60
+ end
61
+ return [max, best]
62
+ end
63
+
64
+ def + ( arg )
65
+ @path + arg.to_s
66
+ end
67
+
68
+ def self.extractable ( aCommand )
69
+ include Extractable
70
+ self.extract_command = aCommand
71
+ end
72
+
73
+ def self.extractable_dir ( aCommand )
74
+ include ExtractableDir
75
+ self.extract_command = aCommand
76
+ end
77
+
78
+ def extractable?
79
+ false
80
+ end
81
+
82
+ def installable?
83
+ false
84
+ end
85
+
86
+ def self.filetype_extension ( anObject, priority=1 )
87
+ class_eval do
88
+ self.extension = anObject
89
+ self.priority = priority
90
+ concrete
91
+ end
92
+ end
93
+
94
+ cattr_accessor :runner
95
+ class_inheritable_accessor :extension
96
+ class_inheritable_accessor :priority # 0 .. +inf
97
+
98
+ self.runner = Commands::Runners::System.new
99
+
100
+ end # class Generic
101
+
102
+
103
+
104
+ class Unknown < Generic
105
+ filetype_extension(/(\.[^.\/]+)?$/, 0)
106
+ end # class Unknown
107
+
108
+
109
+
110
+ class ExtractError < Exception
111
+ end
112
+
113
+
114
+
115
+ module Extractable
116
+
117
+ def self.included ( aClass )
118
+
119
+ aClass.class_inheritable_accessor :extract_command
120
+
121
+ aClass.module_eval do
122
+
123
+ def extractable?
124
+ true
125
+ end
126
+
127
+ def mk_cmd ( out )
128
+ extract_command < @path > out
129
+ end
130
+
131
+ def extract
132
+ base, ext = @base.extsplit
133
+ @tmp = TempPath.new(base.path.basename, ext)
134
+ cmd = mk_cmd(@tmp)
135
+ data = cmd.run(self.class.runner)
136
+ if data.status != 0
137
+ @tmp.rmtree if @tmp.exist?
138
+ raise ExtractError, "Cannot extract a file:
139
+ | path: #{to_s}
140
+ | type: #{self.class}
141
+ | command: #{cmd}
142
+ | exit status: #{data.status.exitstatus}".head_cut!
143
+ end
144
+ FileType.guess(@tmp)
145
+ end
146
+
147
+ alias :default :extract
148
+
149
+ end
150
+
151
+ end
152
+
153
+ end # module Extractable
154
+
155
+
156
+
157
+ # FIXME Use the zlib if gzip not available.
158
+ class Gz < Generic
159
+ filetype_extension(/(\.(gz|z|Z)|-gz|-z|_z)$/)
160
+ extractable GZIP + %w[-d -c %i]
161
+ end # class Gz
162
+
163
+
164
+
165
+ class Bz2 < Generic
166
+ filetype_extension(/\.bz2?$/)
167
+ extractable BZIP2 + %w[-d -c %i]
168
+ end # class Bz2
169
+
170
+
171
+
172
+ class Zip < Generic
173
+ filetype_extension(/\.zip$/)
174
+ extractable UNZIP + %w[-p %i]
175
+ end # class Zip
176
+
177
+
178
+ class CorruptedTarballError < Exception
179
+ end
180
+
181
+
182
+ module ExtractableDir
183
+
184
+ def self.included ( aClass )
185
+
186
+ aClass.module_eval do
187
+
188
+ include Extractable
189
+
190
+ remove_method :mk_cmd
191
+
192
+ def mk_cmd ( out )
193
+ @log = TempPath.new('log')
194
+ cmd = extract_command[@tmp] < @path > @log
195
+ @tmp.mkpath
196
+ cmd
197
+ end
198
+
199
+ alias :extract_extractable :extract
200
+
201
+ def extract
202
+ dir = extract_extractable
203
+ FileType.guess(dir.path + longest_common_path(@log).join('/'))
204
+ end
205
+
206
+ end
207
+
208
+ end
209
+
210
+ # We want the longest common path
211
+ def longest_common_path ( log )
212
+ longest = nil
213
+ raise CorruptedTarballError, 'tar output empty' if log.zero?
214
+ log.each_line do |line|
215
+ line.chomp!
216
+ path = line.split(/\//)
217
+ longest = path if longest.nil?
218
+ longest &= path
219
+ raise CorruptedTarballError, log.read if longest.empty?
220
+ end
221
+ raise CorruptedTarballError, log.read if longest.nil?
222
+ longest
223
+ end
224
+ module_function :longest_common_path
225
+
226
+ end # module ExtractableDir
227
+
228
+
229
+
230
+ class Tar < Generic
231
+ filetype_extension(/\.tar$/)
232
+ extractable_dir TAR + %w[xvf %i -C]
233
+ end # class Tar
234
+
235
+
236
+
237
+ class TarGz < Generic
238
+ filetype_extension(/\.(tar(\.(gz|z|Z)|-gz|-z|_z)|tgz)$/)
239
+ extractable_dir TAR + %w[xvzf %i -C]
240
+ end # class TarGz
241
+
242
+
243
+
244
+ class TarBz2 < Generic
245
+ filetype_extension(/\.(tar\.bz2|tbz2|tbz)$/)
246
+ # FIXME Use this pipe beacause -j is not portable
247
+ # extractable_dir (BZIP2 + %w[-c -d]) | (TAR + %w[xvf - -C])
248
+ # problem: a pipe command doesn't properly implement `[]'
249
+ extractable_dir TAR + %w[xvjf %i -C]
250
+ end # class TarBz2
251
+
252
+
253
+
254
+ class Ruby < Generic
255
+ filetype_extension(/\.rbw?$/)
256
+
257
+ def load
258
+ path.load
259
+ end
260
+
261
+ def require
262
+ path.require
263
+ end
264
+
265
+ end # class Ruby
266
+
267
+
268
+
269
+ class Yaml < Generic
270
+ filetype_extension(/\.ya?ml$/)
271
+
272
+ def load
273
+ YAML::load(path.read)
274
+ end
275
+
276
+ end # class Yaml
277
+
278
+
279
+
280
+ class Gem < Generic
281
+ filetype_extension(/\.gem$/)
282
+
283
+ def installable?
284
+ true
285
+ end
286
+
287
+ def install ( install_dir=nil )
288
+ cmd = GEM + 'install' + path
289
+ cmd << '--install-dir' << install_dir unless install_dir.nil?
290
+ cmd.run(runner)
291
+ end
292
+
293
+ end # class Gem
294
+
295
+
296
+
297
+ class Directory < Generic
298
+ filetype_extension(/()$/)
299
+
300
+ def self.match_type ( path, max, best )
301
+ if path.exist? and path.directory?
302
+ return [path.to_s.size, self]
303
+ end
304
+ return [max, best]
305
+ end
306
+
307
+ end # class Directory
308
+
309
+
310
+
311
+ def self.guess_class ( path )
312
+ lazy_init
313
+ max = -1
314
+ best = Unknown
315
+ path = path.to_path
316
+ @@subclasses.each do |klass|
317
+ max, best = klass.match_type(path, max, best)
318
+ end
319
+ return best
320
+ end
321
+
322
+ def self.guess ( path )
323
+ guess_class(path).new(path)
324
+ end
325
+
326
+ def self.lazy_init
327
+ return if defined? @@init
328
+ @@init = true
329
+ @@subclasses.delete_if do |klass|
330
+ klass.abstract? or not (klass.is_a? Class) # and constants.include? klass)
331
+ end
332
+ @@subclasses.each do |klass|
333
+ ext = klass.extension
334
+ raise ArgumentError, "Bad extension #{ext}" unless ext.is_a? Regexp
335
+ end
336
+ end
337
+
338
+ end # module FileType
339
+
340
+
341
+ test_section __FILE__ do
342
+
343
+ class FileTypeTest < Test::Unit::TestCase
344
+
345
+ def setup
346
+ @tmp = TempPath.new
347
+ (@tmp + 'foo').mkpath
348
+ @mr = Commands::Runners::Mock.new do |out|
349
+ out.write("#@tmp/foo/bar/baz\n#@tmp/foo\n#@tmp/foo/f/f/foo/baz\n")
350
+ end
351
+ FileType::Generic.runner = @mr
352
+ @res_dir = __FILE__.to_path.dirname.parent + 'test/resources'
353
+ end
354
+
355
+ def assert_guess ( type, *files )
356
+ files.flatten.each do |file|
357
+ assert_nothing_raised do
358
+ @file = FileType.guess(file)
359
+ end
360
+ assert_kind_of(FileType.const_get(type), @file)
361
+ end
362
+ end
363
+
364
+ def assert_extract ( type, command, file )
365
+ assert_nothing_raised { @inp = FileType.guess(file) }
366
+ assert(@inp.extractable?, "#@inp not extractable")
367
+ assert_nothing_raised { @res = @inp.extract }
368
+ assert_kind_of(FileType.const_get(type), @res)
369
+ assert_match(command, @mr.log.last.to_sh)
370
+ end
371
+
372
+ def assert_real_extract ( type, file )
373
+ FileType::Generic.runner = Commands::Runners::System.new
374
+ assert_nothing_raised { @inp = FileType.guess(file) }
375
+ assert(@inp.extractable?, "#@inp not extractable")
376
+ assert_nothing_raised { @res = @inp.extract }
377
+ assert_kind_of(FileType.const_get(type), @res)
378
+ end
379
+
380
+ def assert_install ( command, file, *args )
381
+ assert_nothing_raised { @inp = FileType.guess(file) }
382
+ assert(@inp.installable?, "#@inp not installable")
383
+ assert_nothing_raised { @res = @inp.install(*args) }
384
+ assert_match(command, @mr.log.last.to_sh)
385
+ end
386
+
387
+
388
+ def test_gz
389
+ assert_guess :Gz, %w[ foo.gz foo.z foo.Z foo-z foo-gz foo_z ]
390
+ end
391
+ def test_bz2
392
+ assert_guess :Bz2, %w[ foo.bz2 foo.bz ]
393
+ end
394
+ def test_zip
395
+ assert_guess :Zip, %w[ foo.zip ]
396
+ end
397
+ def test_tar_bz2
398
+ assert_guess :TarBz2, %w[ foo.tar.bz2 foo.tbz2 foo/bar.tbz ]
399
+ end
400
+ def test_tar_gz
401
+ assert_guess :TarGz, %w[ foo.tar.gz foo.tgz foo/bar.tar.gz foo.tar.Z ]
402
+ end
403
+ def test_tar
404
+ assert_guess :Tar, %w[ foo.tar /foo/bar.tar ]
405
+ end
406
+ def test_ruby
407
+ assert_guess :Ruby, 'foo.rb', 'foo.rbw'
408
+ end
409
+ def test_yaml
410
+ assert_guess :Yaml, 'foo.yml', 'foo.yaml'
411
+ end
412
+ def test_gem
413
+ assert_guess :Gem, 'foo.gem'
414
+ end
415
+ def test_unknown
416
+ assert_guess :Unknown, 'foo.dne', 'foo', '.foo'
417
+ assert(! @file.extractable?, "#@file is extractable")
418
+ end
419
+ def test_dir
420
+ TempPath.new do |tmp|
421
+ tmp.mkpath
422
+ assert_guess :Directory, tmp, '.', '/', '..'
423
+ end
424
+ end
425
+
426
+ def test_extract_gz
427
+ assert_extract :Ruby, /^"gzip" "-d" "-c" "[^%]*" > "[^%]*"$/, 'foo.rb.gz'
428
+ end
429
+ def test_extract_bz2
430
+ assert_extract :Unknown, /^"bzip2" "-d" "-c" "[^%]*" > "[^%]*"$/, 'foo.bz2'
431
+ end
432
+ def test_extract_zip
433
+ assert_extract :Gz, /^"unzip" "-p" "[^%]*" > "[^%]*"$/, 'foo.gz.zip'
434
+ end
435
+ def test_extract_tar_bz2
436
+ assert_extract :Directory,
437
+ # /^"bzip2" -d -c "foo.tar.bz2" | "tar" "xvf" "-" "-C" "[^%]*" > "[^%]*"$/,
438
+ /^"tar" "xvjf" "foo.tar.bz2" "-C" "[^%]*" > "[^%]*"$/, 'foo.tar.bz2'
439
+ end
440
+ def test_extract_tar_gz
441
+ assert_extract :Directory,
442
+ /^"tar" "xvzf" "foo.tar.gz" "-C" ".*foo.*" > ".*log.*"$/, 'foo.tar.gz'
443
+ assert_real_extract :Directory, @res_dir + 'foo.tar.gz'
444
+ end
445
+ def test_extract_tar
446
+ assert_extract :Directory,
447
+ /^"tar" "xvf" "foo.tar" "-C" "[^%]*" > "[^%]*"$/, 'foo.tar'
448
+ end
449
+
450
+ def test_install_gem
451
+ assert_install(/^"gem" "install" "foo.gem"$/, 'foo.gem')
452
+ assert_install(/^"gem" "install" "foo.gem" "--install-dir" "\/tmp"$/,
453
+ 'foo.gem', '/tmp')
454
+ end
455
+
456
+ def test_longest_common_path
457
+ assert_nothing_raised do
458
+ res = @res_dir + 'tar.gz.log'
459
+ @longest = FileType::ExtractableDir.longest_common_path(res)
460
+ end
461
+ assert_equal(['core_ex-0.1.4'], @longest)
462
+ end
463
+
464
+ end # class FileTypeTest
465
+
466
+ end