xli-dtr 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/README +6 -115
  2. data/Rakefile +22 -154
  3. data/TODO +16 -1
  4. data/bin/dtr +22 -61
  5. data/dtr.gemspec +7 -6
  6. data/lib/dtr/agent/brain.rb +66 -0
  7. data/lib/dtr/agent/herald.rb +50 -0
  8. data/lib/dtr/agent/runner.rb +100 -0
  9. data/lib/dtr/agent/sync_codebase.rb +44 -0
  10. data/lib/dtr/agent/sync_logger.rb +40 -0
  11. data/lib/dtr/agent/test_unit.rb +42 -0
  12. data/lib/dtr/agent/worker.rb +92 -0
  13. data/lib/dtr/agent/working_env_ext.rb +45 -0
  14. data/lib/dtr/agent.rb +37 -0
  15. data/lib/dtr/master.rb +40 -0
  16. data/lib/dtr/monitor.rb +37 -0
  17. data/lib/dtr/raketasks.rb +74 -13
  18. data/lib/dtr/shared/adapter.rb +112 -0
  19. data/lib/dtr/shared/configuration.rb +76 -0
  20. data/lib/dtr/shared/message_decorator.rb +28 -0
  21. data/lib/dtr/shared/ruby_ext.rb +153 -0
  22. data/lib/dtr/shared/service/agent.rb +33 -0
  23. data/lib/dtr/shared/service/file.rb +28 -0
  24. data/lib/dtr/shared/service/rinda.rb +40 -0
  25. data/lib/dtr/shared/service/runner.rb +33 -0
  26. data/lib/dtr/shared/service/working_env.rb +28 -0
  27. data/lib/dtr/shared/service.rb +19 -0
  28. data/lib/dtr/shared/sync_codebase/codebase.rb +32 -0
  29. data/lib/dtr/shared/sync_codebase/master_ext.rb +52 -0
  30. data/lib/dtr/shared/sync_codebase/package.rb +39 -0
  31. data/lib/dtr/shared/sync_codebase/sync_service.rb +41 -0
  32. data/lib/dtr/shared/sync_codebase.rb +18 -0
  33. data/lib/dtr/shared/sync_logger.rb +72 -0
  34. data/lib/dtr/shared/utils/cmd.rb +30 -0
  35. data/lib/dtr/shared/utils/env_store.rb +60 -0
  36. data/lib/dtr/shared/utils/logger.rb +71 -0
  37. data/lib/dtr/shared/utils.rb +17 -0
  38. data/lib/dtr/shared/working_env.rb +38 -0
  39. data/lib/dtr/shared.rb +24 -0
  40. data/lib/dtr/test_unit/drb_test_runner.rb +57 -0
  41. data/lib/dtr/test_unit/injection.rb +30 -0
  42. data/lib/dtr/test_unit/test_case_injection.rb +37 -0
  43. data/lib/dtr/test_unit/testrunnermediator_injection.rb +72 -0
  44. data/lib/dtr/test_unit/thread_safe_test_result.rb +40 -0
  45. data/lib/dtr/test_unit/worker_club.rb +72 -0
  46. data/lib/dtr/test_unit.rb +8 -275
  47. data/lib/dtr/test_unit_injection.rb +0 -1
  48. data/lib/dtr.rb +23 -81
  49. data/test/acceptance/agent_working_env_test.rb +92 -0
  50. data/test/acceptance/dtr_package_task_test.rb +26 -0
  51. data/test/acceptance/general_test.rb +275 -0
  52. data/test/acceptance/sync_codebase_test.rb +67 -0
  53. data/test/acceptance/sync_logger_test.rb +41 -0
  54. data/test/agent_helper.rb +39 -0
  55. data/test/logger_stub.rb +30 -0
  56. data/test/test_helper.rb +43 -0
  57. data/test/unit/adapter_test.rb +107 -0
  58. data/test/unit/test_unit_test.rb +47 -0
  59. data/test/unit/working_env_test.rb +71 -0
  60. data/testdata/Rakefile +15 -0
  61. data/testdata/a_failed_test_case.rb +8 -0
  62. data/testdata/a_file_system_test_case.rb +8 -0
  63. data/testdata/a_test_case.rb +13 -0
  64. data/testdata/a_test_case2.rb +6 -0
  65. data/testdata/an_error_test_case.rb +9 -0
  66. data/testdata/another_project/Rakefile +6 -0
  67. data/testdata/another_project/passed_test_case.rb +7 -0
  68. data/testdata/is_required_by_a_test.rb +9 -0
  69. data/testdata/lib/lib_test_case.rb +7 -0
  70. data/testdata/package_task_test_rakefile +8 -0
  71. data/testdata/scenario_test_case.rb +34 -0
  72. data/testdata/setup_agent_env_test_case.rb +9 -0
  73. data/testdata/should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process/Rakefile +6 -0
  74. data/testdata/should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process/verify_dir_pwd_test_case.rb +10 -0
  75. metadata +72 -18
  76. data/lib/dtr/base.rb +0 -172
  77. data/lib/dtr/runner.rb +0 -270
  78. data/lib/dtr/service_provider.rb +0 -160
@@ -0,0 +1,71 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'dtr/agent/working_env_ext'
3
+ DTR::WorkingEnv.send(:include, DTR::Agent::WorkingEnvExt)
4
+
5
+ class WorkingEnvTest < Test::Unit::TestCase
6
+ def test_identifier_of_working_env
7
+ assert_not_equal DTR::WorkingEnv.new[:identifier], DTR::WorkingEnv.new[:identifier]
8
+ end
9
+
10
+ def test_working_env_equal
11
+ env1 = DTR::WorkingEnv.new
12
+ env2 = DTR::WorkingEnv.new
13
+ assert_not_equal env1, env2
14
+ env2[:identifier] = env1[:identifier]
15
+ assert env1 == env2
16
+ assert env2 != nil
17
+ assert nil != env2
18
+ end
19
+
20
+ def test_working_dir_within_env_should_be_based_on_host_and_pwd
21
+ env = DTR::WorkingEnv.new
22
+ env[:pwd] = 'pwd'
23
+ env[:host] = 'hostname'
24
+ working_dir = nil
25
+ env.within do
26
+ working_dir = Dir.pwd
27
+ end
28
+ assert_equal File.expand_path('hostname/pwd'), working_dir
29
+ ensure
30
+ FileUtils.rm_rf File.expand_path('hostname')
31
+ end
32
+
33
+ def test_should_truncate_pwd_if_it_is_too_long_for_working_dir
34
+ env = DTR::WorkingEnv.new
35
+ env[:pwd] = 'pwd_pwd_pwd_pwd_pwd_pwd_pwd_pwd_pwd_pwd' #40
36
+ env[:host] = 'hostname'
37
+ working_dir = nil
38
+ env.within do
39
+ working_dir = Dir.pwd
40
+ end
41
+ assert_equal File.expand_path('hostname/_pwd_pwd_pwd_pwd_pwd'), working_dir
42
+ ensure
43
+ FileUtils.rm_rf File.expand_path('hostname')
44
+ end
45
+
46
+ def test_should_convert_non_word_and_number_in_dir_string_to_underscore
47
+ env = DTR::WorkingEnv.new
48
+ env[:pwd] = 'pwd pwd' #40
49
+ env[:host] = 'xli.local:1234'
50
+ working_dir = nil
51
+ env.within do
52
+ working_dir = Dir.pwd
53
+ end
54
+ assert_equal File.expand_path('xli_local_1234/pwd_pwd'), working_dir
55
+ ensure
56
+ FileUtils.rm_rf File.expand_path('xli_local_1234')
57
+ end
58
+
59
+ def test_working_dir_should_be_created_if_it_does_not_exist
60
+ env = DTR::WorkingEnv.new
61
+ env[:pwd] = 'pwd'
62
+ env[:host] = 'hostname'
63
+
64
+ assert !File.exists?(File.expand_path('hostname'))
65
+ env.within do
66
+ assert File.exists?(Dir.pwd)
67
+ end
68
+ ensure
69
+ FileUtils.rm_rf File.expand_path('hostname')
70
+ end
71
+ end
data/testdata/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+ require 'dtr/raketasks'
3
+ require 'rake/testtask'
4
+
5
+ desc "Default Task"
6
+ task :default => :dtr
7
+
8
+ DTR::TestTask.new :dtr do |t|
9
+ t.test_files = FileList['*test_case.rb']
10
+ t.processes = 2
11
+ end
12
+
13
+ DTR::PackageTask.new do |p|
14
+ p.package_files.include("**/*")
15
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ class AFailedTestCase < Test::Unit::TestCase
3
+ def test_failed
4
+ assert false
5
+ end
6
+ end
7
+
8
+
@@ -0,0 +1,8 @@
1
+
2
+ require 'test/unit'
3
+ class AFileSystemTestCase < Test::Unit::TestCase
4
+ def test_file_exist
5
+ assert File.exist?(File.dirname(__FILE__) + '/a_file_system_test_case.rb')
6
+ end
7
+ end
8
+
@@ -0,0 +1,13 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/is_required_by_a_test.rb'
3
+ class ATestCase < Test::Unit::TestCase
4
+
5
+ def test_succeeded
6
+ require 'pp'
7
+ assert eval('true')
8
+ assert IsRequiredByATest.ok?
9
+ assert_equal 'test', ENV["RAILS_ENV"]
10
+ end
11
+
12
+ end
13
+
@@ -0,0 +1,6 @@
1
+ require 'test/unit'
2
+ class ATestCase2 < Test::Unit::TestCase
3
+ def test_succeeded
4
+ assert true
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ require 'test/unit'
2
+ class AnErrorTestCase < Test::Unit::TestCase
3
+ class MyError < StandardError
4
+ end
5
+ def test_error
6
+ raise MyError.new('error')
7
+ end
8
+ end
9
+
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
2
+ require 'dtr/raketasks'
3
+
4
+ DTR::PackageTask.new do |p|
5
+ p.package_files.include("**/*")
6
+ end
@@ -0,0 +1,7 @@
1
+ require 'test/unit'
2
+ class PassedTestCase < Test::Unit::TestCase
3
+ def test_succeeded
4
+ assert_equal 'test', 'test'
5
+ end
6
+ end
7
+
@@ -0,0 +1,9 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+
3
+ class IsRequiredByATest
4
+
5
+ def self.ok?
6
+ true
7
+ end
8
+
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'test/unit'
2
+ class LibTestCase < Test::Unit::TestCase
3
+ def test_lib
4
+ assert_equal 2, 2
5
+ end
6
+ end
7
+
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+ require 'dtr/raketasks'
3
+
4
+ DTR::PackageTask.new do |p|
5
+ p.package_files.include("lib/**/*")
6
+ p.package_files.include("*.rb")
7
+ p.package_files.exclude("*test_case.rb")
8
+ end
@@ -0,0 +1,34 @@
1
+ require 'test/unit'
2
+ class ScenarioTestCase < Test::Unit::TestCase
3
+
4
+ def test_run_test_failed
5
+ assert_equal '1', '2'
6
+ end
7
+
8
+ def test_run_test_passed
9
+ assert_eqaul '1', '1'
10
+ end
11
+
12
+ def test_run_test_error
13
+ assert false
14
+ end
15
+
16
+ def test_runner_should_setup_env
17
+ 'should'.raise.error
18
+ end
19
+
20
+ def test_runner_should_not_setup_env_twice
21
+ end
22
+
23
+ def test_runner_should_update_code
24
+ assert_equal ['1'], '1' + nil
25
+ end
26
+
27
+ def test_execution
28
+ assert nil.empty?
29
+ end
30
+
31
+ def test_runner_should_rollback_popped_test
32
+ assert_equal ['1'], '1'
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ require 'test/unit'
2
+ class SetupAgentEnvTestCase < Test::Unit::TestCase
3
+
4
+ def test_setup_agent_env_test_case
5
+ assert File.exists?('/tmp/test_setup_agent_env_from_master_process')
6
+ end
7
+
8
+ end
9
+
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
2
+ require 'dtr/raketasks'
3
+
4
+ DTR::PackageTask.new do |p|
5
+ p.package_files.include("**/*")
6
+ end
@@ -0,0 +1,10 @@
1
+ require 'test/unit'
2
+
3
+ class VerifyDirPwdTestCase < Test::Unit::TestCase
4
+
5
+ def test_should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process
6
+ assert_equal 'should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process', Dir.pwd.split('/').last
7
+ end
8
+
9
+ end
10
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xli-dtr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Li Xiao
@@ -11,16 +11,8 @@ cert_chain: []
11
11
 
12
12
  date: 2008-08-13 00:00:00 -07:00
13
13
  default_executable: dtr
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: daemons
17
- version_requirement:
18
- version_requirements: !ruby/object:Gem::Requirement
19
- requirements:
20
- - - ">"
21
- - !ruby/object:Gem::Version
22
- version: 1.0.7
23
- version:
14
+ dependencies: []
15
+
24
16
  description:
25
17
  email: iam@li-xiao.com
26
18
  executables:
@@ -30,17 +22,51 @@ extensions: []
30
22
  extra_rdoc_files: []
31
23
 
32
24
  files:
33
- - lib/dtr/base.rb
25
+ - lib/dtr/agent/brain.rb
26
+ - lib/dtr/agent/herald.rb
27
+ - lib/dtr/agent/runner.rb
28
+ - lib/dtr/agent/sync_codebase.rb
29
+ - lib/dtr/agent/sync_logger.rb
30
+ - lib/dtr/agent/test_unit.rb
31
+ - lib/dtr/agent/worker.rb
32
+ - lib/dtr/agent/working_env_ext.rb
33
+ - lib/dtr/agent.rb
34
+ - lib/dtr/master.rb
35
+ - lib/dtr/monitor.rb
34
36
  - lib/dtr/raketasks.rb
35
- - lib/dtr/runner.rb
36
- - lib/dtr/service_provider.rb
37
+ - lib/dtr/shared/adapter.rb
38
+ - lib/dtr/shared/configuration.rb
39
+ - lib/dtr/shared/message_decorator.rb
40
+ - lib/dtr/shared/ruby_ext.rb
41
+ - lib/dtr/shared/service/agent.rb
42
+ - lib/dtr/shared/service/file.rb
43
+ - lib/dtr/shared/service/rinda.rb
44
+ - lib/dtr/shared/service/runner.rb
45
+ - lib/dtr/shared/service/working_env.rb
46
+ - lib/dtr/shared/service.rb
47
+ - lib/dtr/shared/sync_codebase/codebase.rb
48
+ - lib/dtr/shared/sync_codebase/master_ext.rb
49
+ - lib/dtr/shared/sync_codebase/package.rb
50
+ - lib/dtr/shared/sync_codebase/sync_service.rb
51
+ - lib/dtr/shared/sync_codebase.rb
52
+ - lib/dtr/shared/sync_logger.rb
53
+ - lib/dtr/shared/utils/cmd.rb
54
+ - lib/dtr/shared/utils/env_store.rb
55
+ - lib/dtr/shared/utils/logger.rb
56
+ - lib/dtr/shared/utils.rb
57
+ - lib/dtr/shared/working_env.rb
58
+ - lib/dtr/shared.rb
59
+ - lib/dtr/test_unit/drb_test_runner.rb
60
+ - lib/dtr/test_unit/injection.rb
61
+ - lib/dtr/test_unit/test_case_injection.rb
62
+ - lib/dtr/test_unit/testrunnermediator_injection.rb
63
+ - lib/dtr/test_unit/thread_safe_test_result.rb
64
+ - lib/dtr/test_unit/worker_club.rb
37
65
  - lib/dtr/test_unit.rb
38
66
  - lib/dtr/test_unit_injection.rb
39
67
  - lib/dtr.rb
40
68
  - bin/dtr
41
- - bin
42
69
  - CHANGES
43
- - doc
44
70
  - dtr.gemspec
45
71
  - install.rb
46
72
  - lib
@@ -74,5 +100,33 @@ rubygems_version: 1.2.0
74
100
  signing_key:
75
101
  specification_version: 2
76
102
  summary: DTR is a distributed test runner to run tests on distributed computers for decreasing build time.
77
- test_files: []
78
-
103
+ test_files:
104
+ - test/acceptance/agent_working_env_test.rb
105
+ - test/acceptance/dtr_package_task_test.rb
106
+ - test/acceptance/general_test.rb
107
+ - test/acceptance/sync_codebase_test.rb
108
+ - test/acceptance/sync_logger_test.rb
109
+ - test/agent_helper.rb
110
+ - test/logger_stub.rb
111
+ - test/test_helper.rb
112
+ - test/unit/adapter_test.rb
113
+ - test/unit/test_unit_test.rb
114
+ - test/unit/working_env_test.rb
115
+ - testdata/a_failed_test_case.rb
116
+ - testdata/a_file_system_test_case.rb
117
+ - testdata/a_test_case.rb
118
+ - testdata/a_test_case2.rb
119
+ - testdata/an_error_test_case.rb
120
+ - testdata/another_project
121
+ - testdata/another_project/passed_test_case.rb
122
+ - testdata/another_project/Rakefile
123
+ - testdata/is_required_by_a_test.rb
124
+ - testdata/lib
125
+ - testdata/lib/lib_test_case.rb
126
+ - testdata/package_task_test_rakefile
127
+ - testdata/Rakefile
128
+ - testdata/scenario_test_case.rb
129
+ - testdata/setup_agent_env_test_case.rb
130
+ - testdata/should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process
131
+ - testdata/should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process/Rakefile
132
+ - testdata/should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process/verify_dir_pwd_test_case.rb
data/lib/dtr/base.rb DELETED
@@ -1,172 +0,0 @@
1
- # Copyright (c) 2007-2008 Li Xiao
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require 'pstore'
16
-
17
- require 'logger'
18
-
19
- class Array
20
- def blank?
21
- empty?
22
- end
23
- end
24
-
25
- class NilClass
26
- def blank?
27
- true
28
- end
29
- end
30
-
31
- module DTR
32
-
33
- MESSAGE_KEY = :message
34
-
35
- def logger
36
- return DTROPTIONS[:logger] if DTROPTIONS[:logger]
37
- DTROPTIONS[:logger] = if DTROPTIONS[:log_level] == Logger::DEBUG
38
- Logger.new(STDOUT)
39
- else
40
- log_file = if File.exist?('log')
41
- File.join("log", DTROPTIONS[:log_file] || 'dtr.log')
42
- else
43
- DTROPTIONS[:log_file] || 'dtr.log'
44
- end
45
- Logger.new("./#{log_file}", 1, 5*1024*1024)
46
- end
47
- DTROPTIONS[:logger].datetime_format = "%m-%d %H:%M:%S"
48
- DTROPTIONS[:logger].level = DTROPTIONS[:log_level] || Logger::INFO
49
- DTROPTIONS[:logger]
50
- end
51
-
52
- def debug(message=nil, &block)
53
- output(:debug, message, &block)
54
- end
55
-
56
- def info(message=nil, &block)
57
- output(:info, message, &block)
58
- end
59
-
60
- def error(message=nil, &block)
61
- output(:error, message, &block)
62
- end
63
-
64
- def output(level, msg=nil, &block)
65
- logger.send(level) do
66
- message = block_given? ? block.call : msg.to_s
67
- EnvStore.new << [MESSAGE_KEY, "[#{Process.pid}-#{level.to_s.upcase}] #{message}"] if DTROPTIONS[:run_with_monitor]
68
- message
69
- end
70
- end
71
-
72
- def silent?
73
- logger.level == Logger::ERROR
74
- end
75
-
76
- def with_monitor
77
- DTROPTIONS[:run_with_monitor] = true
78
- EnvStore.new[MESSAGE_KEY] = []
79
- yield
80
- rescue Exception => e
81
- info {"stopping by Exception => #{e.class.name}, message => #{e.message}"}
82
- wait_times = 0
83
- until EnvStore.new[MESSAGE_KEY].empty? || wait_times > 14
84
- wait_times += 1
85
- sleep(1)
86
- end
87
- raise e
88
- end
89
-
90
- module_function :debug, :info, :error, :output, :with_monitor, :logger, :silent?
91
-
92
- class CmdInterrupt < StandardError; end
93
-
94
- class Cmd
95
- def self.execute(cmd)
96
- return true if cmd.nil? || cmd.empty?
97
- DTR.info {"Executing: #{cmd.inspect}"}
98
- output = %x[#{cmd} 2>&1]
99
- DTR.info {"Execution is done, status: #{$?.exitstatus}"}
100
- DTR.error {"#{cmd.inspect} output:\n#{output}"} if $?.exitstatus != 0
101
- $?.exitstatus == 0
102
- end
103
- end
104
-
105
- class EnvStore
106
-
107
- FILE_NAME = '.dtr_env_pstore'
108
-
109
- def self.destroy
110
- File.delete(FILE_NAME) if File.exist?(FILE_NAME)
111
- end
112
-
113
- def [](key)
114
- return nil unless File.exist?(FILE_NAME)
115
-
116
- repository = PStore.new(FILE_NAME)
117
- repository.transaction(true) do
118
- repository[key]
119
- end
120
- end
121
-
122
- def []=(key, value)
123
- repository = PStore.new(FILE_NAME)
124
- repository.transaction do
125
- repository[key] = value
126
- end
127
- end
128
-
129
- def <<(key_value)
130
- key, value = key_value
131
- repository = PStore.new(FILE_NAME)
132
- repository.transaction do
133
- repository[key] = (repository[key] || []) << value
134
- end
135
- end
136
-
137
- def shift(key)
138
- repository = PStore.new(FILE_NAME)
139
- repository.transaction do
140
- if array = repository[key]
141
- array.shift
142
- repository[key] = array
143
- end
144
- end
145
- end
146
- end
147
-
148
- class WorkingEnv
149
-
150
- @@current = nil
151
- def self.refresh
152
- @@current = self.new
153
- end
154
-
155
- def self.current
156
- @@current
157
- end
158
-
159
- def initialize
160
- files = (defined?($argv_dup) ? $argv_dup : []).dup
161
- @env = {:libs => $LOAD_PATH.dup, :files => files, :created_at => Time.now.to_s, :dtr_master_env => ENV['DTR_MASTER_ENV'], :identifier => "#{Time.now.to_s}:#{rand}:#{object_id}"}
162
- end
163
-
164
- def [](key)
165
- @env[key]
166
- end
167
-
168
- def to_s
169
- @env.inspect
170
- end
171
- end
172
- end