TwP-logging 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,5 +1,12 @@
1
- == 0.9.7 / 2009-02-
1
+ == 0.9.8 / 2009-04-11
2
2
 
3
+ 1 minor enhancement
4
+ - Adding a to_s method to the StringIo appender's StringIO object
5
+
6
+ == 0.9.7 / 2009-03-17
7
+
8
+ 1 minor enhancement
9
+ - Added a StringIO appender
3
10
  1 bug fix
4
11
  - Handling objects that cannot be dumped via YAML [Tim Galeckas]
5
12
 
data/lib/logging.rb CHANGED
@@ -8,16 +8,12 @@ begin require 'fastthread'; rescue LoadError; end
8
8
 
9
9
  # TODO: Windows Log Service appender
10
10
 
11
- # TODO: Option to buffer log messages at the appender level
12
- # extend the concept found in the e-mail appender into the other IO
13
- # appenders
14
-
15
11
  #
16
12
  #
17
13
  module Logging
18
14
 
19
15
  # :stopdoc:
20
- VERSION = '0.9.7'
16
+ VERSION = '0.9.8'
21
17
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
22
18
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
23
19
  WIN32 = %r/djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM
@@ -0,0 +1,69 @@
1
+
2
+ require 'stringio'
3
+
4
+ module Logging::Appenders
5
+
6
+ # This class provides an Appender that can write to a StringIO instance.
7
+ # This is very useful for testing log message output.
8
+ #
9
+ class StringIo < ::Logging::Appenders::IO
10
+
11
+ # The StringIO instance the appender is writing to.
12
+ attr_reader :sio
13
+
14
+ # call-seq:
15
+ # StringIo.new( name, opts = {} )
16
+ #
17
+ # Creates a new StrinIo appender that will append log messages to a
18
+ # StringIO instance.
19
+ #
20
+ def initialize( name, opts = {} )
21
+ @sio = StringIO.new
22
+ @sio.extend IoToS
23
+ super(name, @sio, opts)
24
+ clear
25
+ end
26
+
27
+ # Read a single line of text from the internal StringIO instance. +nil+
28
+ # is returned if the StringIO buffer is empty.
29
+ #
30
+ def readline
31
+ sync {
32
+ begin
33
+ @sio.seek @pos
34
+ line = @sio.readline
35
+ @pos = @sio.tell
36
+ line
37
+ rescue EOFError
38
+ nil
39
+ end
40
+ }
41
+ end
42
+
43
+ # Clears the internal StringIO instance. All log messages are removed
44
+ # from the buffer.
45
+ #
46
+ def clear
47
+ sync {
48
+ @pos = 0
49
+ @sio.seek 0
50
+ @sio.truncate 0
51
+ }
52
+ end
53
+ alias :reset :clear
54
+
55
+ # :stopdoc:
56
+ module IoToS
57
+ def to_s
58
+ seek 0
59
+ str = read
60
+ seek 0
61
+ return str
62
+ end
63
+ end
64
+ # :startdoc:
65
+
66
+ end # class StringIo
67
+ end # module Logging::Appenders
68
+
69
+ # EOF
data/logging.gemspec CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{logging}
5
- s.version = "0.9.7"
5
+ s.version = "0.9.8"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Tim Pease"]
9
- s.date = %q{2009-02-23}
9
+ s.date = %q{2009-04-11}
10
10
  s.description = %q{Logging is a flexible logging library for use in Ruby programs based on the design of Java's log4j library. It features a hierarchical logging system, custom level names, multiple output destinations per log event, custom formatting, and more.}
11
11
  s.email = %q{tim.pease@gmail.com}
12
12
  s.extra_rdoc_files = ["History.txt", "README.rdoc"]
13
- s.files = ["History.txt", "README.rdoc", "Rakefile", "data/bad_logging_1.rb", "data/bad_logging_2.rb", "data/logging.rb", "data/logging.yaml", "data/simple_logging.rb", "lib/logging.rb", "lib/logging/appender.rb", "lib/logging/appenders/buffering.rb", "lib/logging/appenders/console.rb", "lib/logging/appenders/email.rb", "lib/logging/appenders/file.rb", "lib/logging/appenders/growl.rb", "lib/logging/appenders/io.rb", "lib/logging/appenders/rolling_file.rb", "lib/logging/appenders/syslog.rb", "lib/logging/config/configurator.rb", "lib/logging/config/yaml_configurator.rb", "lib/logging/layout.rb", "lib/logging/layouts/basic.rb", "lib/logging/layouts/pattern.rb", "lib/logging/log_event.rb", "lib/logging/logger.rb", "lib/logging/repository.rb", "lib/logging/root_logger.rb", "lib/logging/stats.rb", "lib/logging/utils.rb", "logging.gemspec", "test/appenders/test_buffered_io.rb", "test/appenders/test_console.rb", "test/appenders/test_email.rb", "test/appenders/test_file.rb", "test/appenders/test_growl.rb", "test/appenders/test_io.rb", "test/appenders/test_rolling_file.rb", "test/appenders/test_syslog.rb", "test/benchmark.rb", "test/config/test_configurator.rb", "test/config/test_yaml_configurator.rb", "test/layouts/test_basic.rb", "test/layouts/test_pattern.rb", "test/setup.rb", "test/test_appender.rb", "test/test_layout.rb", "test/test_log_event.rb", "test/test_logger.rb", "test/test_logging.rb", "test/test_repository.rb", "test/test_root_logger.rb", "test/test_stats.rb", "test/test_utils.rb"]
13
+ s.files = ["History.txt", "README.rdoc", "Rakefile", "data/bad_logging_1.rb", "data/bad_logging_2.rb", "data/logging.rb", "data/logging.yaml", "data/simple_logging.rb", "lib/logging.rb", "lib/logging/appender.rb", "lib/logging/appenders/buffering.rb", "lib/logging/appenders/console.rb", "lib/logging/appenders/email.rb", "lib/logging/appenders/file.rb", "lib/logging/appenders/growl.rb", "lib/logging/appenders/io.rb", "lib/logging/appenders/rolling_file.rb", "lib/logging/appenders/string_io.rb", "lib/logging/appenders/syslog.rb", "lib/logging/config/configurator.rb", "lib/logging/config/yaml_configurator.rb", "lib/logging/layout.rb", "lib/logging/layouts/basic.rb", "lib/logging/layouts/pattern.rb", "lib/logging/log_event.rb", "lib/logging/logger.rb", "lib/logging/repository.rb", "lib/logging/root_logger.rb", "lib/logging/stats.rb", "lib/logging/utils.rb", "logging.gemspec", "test/appenders/test_buffered_io.rb", "test/appenders/test_console.rb", "test/appenders/test_email.rb", "test/appenders/test_file.rb", "test/appenders/test_growl.rb", "test/appenders/test_io.rb", "test/appenders/test_rolling_file.rb", "test/appenders/test_syslog.rb", "test/benchmark.rb", "test/config/test_configurator.rb", "test/config/test_yaml_configurator.rb", "test/layouts/test_basic.rb", "test/layouts/test_pattern.rb", "test/setup.rb", "test/test_appender.rb", "test/test_layout.rb", "test/test_log_event.rb", "test/test_logger.rb", "test/test_logging.rb", "test/test_repository.rb", "test/test_root_logger.rb", "test/test_stats.rb", "test/test_utils.rb"]
14
14
  s.has_rdoc = true
15
15
  s.homepage = %q{http://logging.rubyforge.org/}
16
16
  s.rdoc_options = ["--main", "README.rdoc"]
@@ -27,15 +27,15 @@ Gem::Specification.new do |s|
27
27
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
28
  s.add_runtime_dependency(%q<flexmock>, [">= 0.8.2"])
29
29
  s.add_runtime_dependency(%q<lockfile>, [">= 1.4.3"])
30
- s.add_development_dependency(%q<bones>, [">= 2.4.0"])
30
+ s.add_development_dependency(%q<bones>, [">= 2.5.0"])
31
31
  else
32
32
  s.add_dependency(%q<flexmock>, [">= 0.8.2"])
33
33
  s.add_dependency(%q<lockfile>, [">= 1.4.3"])
34
- s.add_dependency(%q<bones>, [">= 2.4.0"])
34
+ s.add_dependency(%q<bones>, [">= 2.5.0"])
35
35
  end
36
36
  else
37
37
  s.add_dependency(%q<flexmock>, [">= 0.8.2"])
38
38
  s.add_dependency(%q<lockfile>, [">= 1.4.3"])
39
- s.add_dependency(%q<bones>, [">= 2.4.0"])
39
+ s.add_dependency(%q<bones>, [">= 2.5.0"])
40
40
  end
41
41
  end
@@ -12,11 +12,10 @@ module TestAppenders
12
12
  ::Logging.init
13
13
  @levels = ::Logging::LEVELS
14
14
 
15
- @sio = StringIO.new
16
- @appender = ::Logging::Appenders::IO.new(
17
- 'test_appender', @sio,
18
- :auto_flushing => 3, :immediate_at => :error
15
+ @appender = ::Logging::Appenders::StringIo.new(
16
+ 'test_appender', :auto_flushing => 3, :immediate_at => :error
19
17
  )
18
+ @sio = @appender.sio
20
19
 
21
20
  begin readline rescue EOFError end
22
21
  end
@@ -25,10 +24,10 @@ module TestAppenders
25
24
  event = ::Logging::LogEvent.new('TestLogger', @levels['warn'],
26
25
  [1, 2, 3, 4], false)
27
26
  @appender.append event
28
- assert_raise(EOFError) {readline}
27
+ assert_nil(readline)
29
28
 
30
29
  @appender.append event
31
- assert_raise(EOFError) {readline}
30
+ assert_nil(readline)
32
31
 
33
32
  event.level = @levels['debug']
34
33
  event.data = 'the big log message'
@@ -37,7 +36,7 @@ module TestAppenders
37
36
  assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
38
37
  assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
39
38
  assert_equal "DEBUG TestLogger : the big log message\n", readline
40
- assert_raise(EOFError) {readline}
39
+ assert_nil(readline)
41
40
 
42
41
  @appender.close
43
42
  assert_raise(RuntimeError) {@appender.append event}
@@ -46,10 +45,8 @@ module TestAppenders
46
45
  def test_append_error
47
46
  # setup an internal logger to capture error messages from the IO
48
47
  # appender
49
- log = StringIO.new
50
- Logging::Logger[Logging].add_appenders(
51
- Logging::Appenders::IO.new('__internal_io', log)
52
- )
48
+ log = Logging::Appenders::StringIo.new('__internal_io')
49
+ Logging::Logger[Logging].add_appenders(log)
53
50
  Logging::Logger[Logging].level = 'all'
54
51
 
55
52
 
@@ -58,15 +55,12 @@ module TestAppenders
58
55
  event = ::Logging::LogEvent.new('TestLogger', @levels['warn'],
59
56
  [1, 2, 3, 4], false)
60
57
  @appender.append event
61
- log.seek 0
62
- assert_raise(EOFError) {log.readline}
58
+ assert_nil(log.readline)
63
59
 
64
60
  @appender.append event
65
- log.seek 0
66
- assert_raise(EOFError) {log.readline}
61
+ assert_nil(log.readline)
67
62
 
68
63
  @appender.append event
69
- log.seek 0
70
64
  assert_equal "INFO Logging : appender \"test_appender\" has been disabled", log.readline.strip
71
65
  assert_equal "ERROR Logging : <IOError> not opened for writing", log.readline.strip
72
66
 
@@ -92,17 +86,17 @@ module TestAppenders
92
86
 
93
87
  def test_concat
94
88
  @appender << "this is a test message\n"
95
- assert_raise(EOFError) {readline}
89
+ assert_nil(readline)
96
90
 
97
91
  @appender << "this is another message\n"
98
- assert_raise(EOFError) {readline}
92
+ assert_nil(readline)
99
93
 
100
94
  @appender << "some other line\n"
101
95
 
102
96
  assert_equal "this is a test message\n", readline
103
97
  assert_equal "this is another message\n", readline
104
98
  assert_equal "some other line\n", readline
105
- assert_raise(EOFError) {readline}
99
+ assert_nil(readline)
106
100
 
107
101
  @appender.close
108
102
  assert_raise(RuntimeError) {@appender << 'message'}
@@ -111,24 +105,19 @@ module TestAppenders
111
105
  def test_concat_error
112
106
  # setup an internal logger to capture error messages from the IO
113
107
  # appender
114
- log = StringIO.new
115
- Logging::Logger[Logging].add_appenders(
116
- Logging::Appenders::IO.new('__internal_io', log)
117
- )
108
+ log = Logging::Appenders::StringIo.new('__internal_io')
109
+ Logging::Logger[Logging].add_appenders(log)
118
110
  Logging::Logger[Logging].level = 'all'
119
111
 
120
112
  # close the string IO object so we get an error
121
113
  @sio.close
122
114
  @appender << 'oopsy'
123
- log.seek 0
124
- assert_raise(EOFError) {log.readline}
115
+ assert_nil(log.readline)
125
116
 
126
117
  @appender << 'whoopsy'
127
- log.seek 0
128
- assert_raise(EOFError) {log.readline}
118
+ assert_nil(log.readline)
129
119
 
130
120
  @appender << 'pooh'
131
- log.seek 0
132
121
  assert_equal "INFO Logging : appender \"test_appender\" has been disabled", log.readline.strip
133
122
  assert_equal "ERROR Logging : <IOError> not opened for writing", log.readline.strip
134
123
 
@@ -143,19 +132,19 @@ module TestAppenders
143
132
  def @sio.flush() @ary << :flush end
144
133
 
145
134
  @appender << "this is a test message\n"
146
- assert_raise(EOFError) {readline}
135
+ assert_nil(readline)
147
136
 
148
137
  @appender.flush
149
138
  assert_equal :flush, ary.pop
150
139
  assert_equal "this is a test message\n", readline
151
- assert_raise(EOFError) {readline}
140
+ assert_nil(readline)
152
141
  end
153
142
 
154
143
  def test_immediate_at
155
144
  event = ::Logging::LogEvent.new('TestLogger', @levels['warn'],
156
145
  [1, 2, 3, 4], false)
157
146
  @appender.append event
158
- assert_raise(EOFError) {readline}
147
+ assert_nil(readline)
159
148
 
160
149
  event.level = @levels['error']
161
150
  event.data = 'an error message'
@@ -163,16 +152,12 @@ module TestAppenders
163
152
 
164
153
  assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
165
154
  assert_equal "ERROR TestLogger : an error message\n", readline
166
- assert_raise(EOFError) {readline}
155
+ assert_nil(readline)
167
156
  end
168
157
 
169
158
  private
170
159
  def readline
171
- @pos ||= 0
172
- @sio.seek @pos
173
- line = @sio.readline
174
- @pos = @sio.tell
175
- line
160
+ @appender.readline
176
161
  end
177
162
 
178
163
  end # class TestBufferedIO
@@ -12,9 +12,8 @@ module TestAppenders
12
12
  ::Logging.init
13
13
  @levels = ::Logging::LEVELS
14
14
 
15
- @sio = StringIO.new
16
- @appender = ::Logging::Appenders::IO.new 'test_appender', @sio
17
- begin readline rescue EOFError end
15
+ @appender = ::Logging::Appenders::StringIo.new 'test_appender'
16
+ @sio = @appender.sio
18
17
  end
19
18
 
20
19
  def test_append
@@ -22,13 +21,13 @@ module TestAppenders
22
21
  [1, 2, 3, 4], false)
23
22
  @appender.append event
24
23
  assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
25
- assert_raise(EOFError) {readline}
24
+ assert_nil(readline)
26
25
 
27
26
  event.level = @levels['debug']
28
27
  event.data = 'the big log message'
29
28
  @appender.append event
30
29
  assert_equal "DEBUG TestLogger : the big log message\n", readline
31
- assert_raise(EOFError) {readline}
30
+ assert_nil(readline)
32
31
 
33
32
  @appender.close
34
33
  assert_raise(RuntimeError) {@appender.append event}
@@ -37,20 +36,16 @@ module TestAppenders
37
36
  def test_append_error
38
37
  # setup an internal logger to capture error messages from the IO
39
38
  # appender
40
- log = StringIO.new
41
- Logging::Logger[Logging].add_appenders(
42
- Logging::Appenders::IO.new('__internal_io', log)
43
- )
39
+ log = Logging::Appenders::StringIo.new('__internal_io')
40
+ Logging::Logger[Logging].add_appenders(log)
44
41
  Logging::Logger[Logging].level = 'all'
45
42
 
46
-
47
43
  # close the string IO object so we get an error
48
44
  @sio.close
49
45
  event = ::Logging::LogEvent.new('TestLogger', @levels['warn'],
50
46
  [1, 2, 3, 4], false)
51
47
  @appender.append event
52
48
 
53
- log.seek 0
54
49
  assert_equal "INFO Logging : appender \"test_appender\" has been disabled", log.readline.strip
55
50
  assert_equal "ERROR Logging : <IOError> not opened for writing", log.readline.strip
56
51
 
@@ -77,13 +72,13 @@ module TestAppenders
77
72
  def test_concat
78
73
  @appender << "this is a test message\n"
79
74
  assert_equal "this is a test message\n", readline
80
- assert_raise(EOFError) {readline}
75
+ assert_nil(readline)
81
76
 
82
77
  @appender << "this is another message\n"
83
78
  @appender << "some other line\n"
84
79
  assert_equal "this is another message\n", readline
85
80
  assert_equal "some other line\n", readline
86
- assert_raise(EOFError) {readline}
81
+ assert_nil(readline)
87
82
 
88
83
  @appender.close
89
84
  assert_raise(RuntimeError) {@appender << 'message'}
@@ -92,17 +87,14 @@ module TestAppenders
92
87
  def test_concat_error
93
88
  # setup an internal logger to capture error messages from the IO
94
89
  # appender
95
- log = StringIO.new
96
- Logging::Logger[Logging].add_appenders(
97
- Logging::Appenders::IO.new('__internal_io', log)
98
- )
90
+ log = Logging::Appenders::StringIo.new('__internal_io')
91
+ Logging::Logger[Logging].add_appenders(log)
99
92
  Logging::Logger[Logging].level = 'all'
100
93
 
101
94
  # close the string IO object so we get an error
102
95
  @sio.close
103
96
  @appender << 'oopsy'
104
97
 
105
- log.seek 0
106
98
  assert_equal "INFO Logging : appender \"test_appender\" has been disabled", log.readline.strip
107
99
  assert_equal "ERROR Logging : <IOError> not opened for writing", log.readline.strip
108
100
 
@@ -127,11 +119,7 @@ module TestAppenders
127
119
 
128
120
  private
129
121
  def readline
130
- @pos ||= 0
131
- @sio.seek @pos
132
- line = @sio.readline
133
- @pos = @sio.tell
134
- line
122
+ @appender.readline
135
123
  end
136
124
 
137
125
  end # class TestIO
data/test/benchmark.rb CHANGED
@@ -18,7 +18,6 @@ rescue LoadError
18
18
  end
19
19
 
20
20
  require 'benchmark'
21
- require 'stringio'
22
21
  require 'logger'
23
22
 
24
23
  module Logging
data/test/setup.rb CHANGED
@@ -7,7 +7,6 @@ LOGGING_TEST_SETUP = true
7
7
  require 'rubygems'
8
8
  require 'test/unit'
9
9
  require 'fileutils'
10
- require 'stringio'
11
10
  begin
12
11
  require 'turn'
13
12
  rescue LoadError; end
data/test/test_logger.rb CHANGED
@@ -20,8 +20,8 @@ module TestLogging
20
20
  root = ::Logging::Logger[:root]
21
21
  root.level = 'info'
22
22
 
23
- a1 = SioAppender.new 'a1'
24
- a2 = SioAppender.new 'a2'
23
+ a1 = ::Logging::Appenders::StringIo.new 'a1'
24
+ a2 = ::Logging::Appenders::StringIo.new 'a2'
25
25
  log = ::Logging::Logger.new 'A Logger'
26
26
 
27
27
  root.add_appenders a1
@@ -214,8 +214,8 @@ module TestLogging
214
214
  end
215
215
 
216
216
  def test_concat
217
- a1 = SioAppender.new 'a1'
218
- a2 = SioAppender.new 'a2'
217
+ a1 = ::Logging::Appenders::StringIo.new 'a1'
218
+ a2 = ::Logging::Appenders::StringIo.new 'a2'
219
219
  log = ::Logging::Logger.new 'A'
220
220
 
221
221
  ::Logging::Logger[:root].add_appenders a1
@@ -414,8 +414,8 @@ module TestLogging
414
414
  root = ::Logging::Logger[:root]
415
415
  root.level = 'info'
416
416
 
417
- a1 = SioAppender.new 'a1'
418
- a2 = SioAppender.new 'a2'
417
+ a1 = ::Logging::Appenders::StringIo.new 'a1'
418
+ a2 = ::Logging::Appenders::StringIo.new 'a2'
419
419
  log = ::Logging::Logger.new 'A Logger'
420
420
 
421
421
  root.add_appenders a1
@@ -645,6 +645,7 @@ module TestLogging
645
645
  log_d = ::Logging::Logger['A-logger::D-logger']
646
646
 
647
647
  sio = StringIO.new
648
+ sio.extend ::Logging::Appenders::StringIo::IoToS
648
649
 
649
650
  log_a._dump_configuration( sio )
650
651
  assert_equal(
@@ -697,38 +698,6 @@ module TestLogging
697
698
  end
698
699
 
699
700
  end # class TestLogger
700
-
701
- class SioAppender < ::Logging::Appenders::IO
702
-
703
- def initialize( name, opts = {} )
704
- @sio = StringIO.new
705
- super(name, @sio, opts)
706
- begin readline rescue EOFError end
707
- end
708
-
709
- def readline
710
- @pos ||= 0
711
- @sio.seek @pos
712
- begin
713
- line = @sio.readline
714
- @pos = @sio.tell
715
- line
716
- rescue EOFError
717
- nil
718
- end
719
- end
720
-
721
- end # class SioAppender
722
-
723
701
  end # module TestLogging
724
702
 
725
- class StringIO
726
- def to_s
727
- seek 0
728
- str = read
729
- seek 0
730
- return str
731
- end
732
- end
733
-
734
703
  # EOF
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: TwP-logging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Pease
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-23 00:00:00 -08:00
12
+ date: 2009-04-11 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 2.4.0
43
+ version: 2.5.0
44
44
  version:
45
45
  description: Logging is a flexible logging library for use in Ruby programs based on the design of Java's log4j library. It features a hierarchical logging system, custom level names, multiple output destinations per log event, custom formatting, and more.
46
46
  email: tim.pease@gmail.com
@@ -69,6 +69,7 @@ files:
69
69
  - lib/logging/appenders/growl.rb
70
70
  - lib/logging/appenders/io.rb
71
71
  - lib/logging/appenders/rolling_file.rb
72
+ - lib/logging/appenders/string_io.rb
72
73
  - lib/logging/appenders/syslog.rb
73
74
  - lib/logging/config/configurator.rb
74
75
  - lib/logging/config/yaml_configurator.rb