text-to-noise 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  Gemfile.lock
4
4
  pkg/*
5
5
  tmp/*
6
+ log/*
6
7
 
7
8
  # osx noise
8
9
  .DS_Store
data/README.md CHANGED
@@ -19,13 +19,27 @@ Stuff that I had to do to get this running:
19
19
  2. Install `text_to_noise` via [Rubygems][rubygems]:
20
20
  `gem install text-to-noise`
21
21
 
22
+ Usage
23
+ -----
24
+
25
+ First, create a sound mapping configuration as shown below. Then you can pipe
26
+ a log into the `text_to_noise` script and it will start chirping:
27
+
28
+ tail -f /var/log/mylog | text_to_noise my.sounds.rb
29
+
30
+ Alternatively, you can run `text_to_noise` on an existing file:
31
+
32
+ text_to_noise my.sounds.rb -f file.log
33
+
34
+ Text-To-Noise will cease processing when it reaches the end of the file.
35
+
22
36
 
23
37
  Configuration
24
38
  =============
25
39
 
26
40
  Text-To-Noise is configured with a Ruby file. The configuration contains a set
27
41
  of rules for mapping a line of input text to a sound. Each mapping is a single
28
- method of the form `map( pattern ).to "sound"`.
42
+ method of the form `map( pattern ).to "sound"`:
29
43
 
30
44
  map( /a regex matching log lines to trigger sounds/ ).to "a sound name to play"
31
45
 
@@ -55,9 +69,23 @@ object returned from the regular expression match:
55
69
  match_data[1].to_i > 500
56
70
  }.to "vulture"
57
71
 
58
- The above rule will play a vulture sound iff a line matches the expression _and_ the block
59
- returns true. Applied to a Rails log, the above rule will play a vulture sound whenever a
60
- page takes longer than 500ms to render.
72
+ The above rule will play a vulture sound **iff** a line matches the expression
73
+ _and_ the block returns true. Applied to a Rails log, the above rule will play
74
+ a vulture sound whenever a page takes longer than 500ms to render.
75
+
76
+ Additional patterns may be added with the `when` condition:
77
+
78
+ map( /Completed in (\d+)ms/ ) { |match_data|
79
+ match_data[1].to_i > 500
80
+ }.when { |match_data|
81
+ match_data[1].to_i < 55
82
+ }.to "vulture"
83
+
84
+ The sound will play if _any_ of the given conditions match.
85
+
86
+ Since the configuration file is Ruby, you could conceivable do just about
87
+ anything you want in the condition block.
88
+
61
89
 
62
90
  For additional details, see the Cucumber [features][Features]. Also, have a
63
91
  look at the [sample][SampleConfig] configuration.
@@ -87,6 +115,7 @@ configurations:
87
115
  mockingbird
88
116
  nightingale
89
117
  owl
118
+ owl-short
90
119
  peacock
91
120
  pigeons
92
121
  red_lories
@@ -94,23 +123,60 @@ configurations:
94
123
  vulture
95
124
  whipperwhill
96
125
 
97
- Soon you'll be able to add your own `wav` files for playback, but not just yet.
98
126
 
127
+ Adding Your Own Sounds
128
+ ----------------------
99
129
 
100
- Usage
101
- -----
130
+ To make your own sounds available for play, add `sound_path` declarations to
131
+ your mapping configuration:
102
132
 
103
- First, create a sound mapping configuration as shown above. Then you can pipe
104
- a log into the `text_to_noise` script and it will start chirping:
133
+ sound_path "my_sounds/jungle"
134
+ sound_path "my_sounds/circus"
105
135
 
106
- tail -f /var/log/mylog | text_to_noise -c my.sounds.rb
136
+ map /Session/ => "clown"
137
+ map /404/ => "monkeys"
107
138
 
108
- Alternatively, you can run `text_to_noise` on an existing file:
139
+ Each `sound_path` is a directory containing wav files. Now you can specify
140
+ mappings to wav files in the specified directories. As with the included
141
+ sounds, the '.wav' extension is optional.
142
+
143
+
144
+
145
+ Example
146
+ =======
147
+
148
+ Here's a starting point if you're sampling a Rails log:
109
149
 
110
- text_to_noise -c my.sounds.rb -f file.log
150
+ # rails.configuration.rb
151
+ sound_path "tmp/sounds" # if you've got some of your own sounds you'd like to try
152
+
153
+ map /Rendered/ => %w(cardinal crickets canary), :every => 6
154
+ map /Processing/ => "crickets", :every => 4
155
+
156
+ map /User Load/ => %w(nightingale crickets canary)
157
+ map /SessionsController#new/ => "owl-short"
158
+
159
+ map /404 Not Found/ => "hawk"
160
+ map /RoutingError/ => "hawk"
161
+
162
+ map( /Completed in (\d+)ms/ ) { |match_data|
163
+ match_data[1].to_i > 500
164
+ }
165
+
166
+ Start it up with:
167
+
168
+ tail -f /var/www/myrailsapp/shared/logs/production.log | text_to_noise sample.configuration.rb
169
+
170
+ Or perhaps you're interested in SSH activity on your server:
171
+
172
+ # ssh.sounds.rb
173
+ match /sshd.*Accepted/ => %w[rooster hawk chicken crow]
111
174
 
112
- Text-To-Noise will cease processing when it reaches the end of the file.
175
+ Get this started with:
113
176
 
177
+ echo 'match /sshd.*Accepted/ => %w[rooster hawk chicken crow]' > ssh.sounds.rb
178
+ tail -f /var/log/secure.log | text_to_noise ssh.sounds.rb
179
+
114
180
 
115
181
  TODO
116
182
  ----
@@ -118,12 +184,8 @@ TODO
118
184
  At the moment, this only supports playing some free bird songs that are included in the gem.
119
185
  Highest priority is the ability to add your own sound sets for playback.
120
186
 
121
- * Add sounds to the available noises for playback
122
187
  * Capistrano integration
123
188
  * Automatically refresh configurations
124
- * Add an 'every' option to throttle sounds for comman events
125
- * Add generators to create stub configurations
126
- * Support sound themes?
127
189
 
128
190
 
129
191
  [Homebrew]:http://mxcl.github.com/homebrew
@@ -19,8 +19,6 @@ arg_parser = OptionParser.new do |opts|
19
19
 
20
20
  opts.on( "-f", "--file FILE",
21
21
  "Read input from FILE. Defaults to stdin" ) { |f| options[:input] = File.open( f, "r" ) }
22
- opts.on( "-c", "--config MAPPING_CONFIG",
23
- "Read input to sound mapping configuration from MAPPING_CONFIG" ) { |c| options[:config] = c }
24
22
  opts.on( "-m", "--mute",
25
23
  "Don't play any sounds, just print what matched" ) { options[:mute] = true }
26
24
  opts.on( "-t", "--throttle DELAY",
@@ -32,18 +30,18 @@ arg_parser = OptionParser.new do |opts|
32
30
  end
33
31
  end
34
32
 
35
- arg_parser.parse!
33
+ mapping_files = arg_parser.parse!
36
34
 
37
35
  begin
38
- TextToNoise::CommandLine.new( options ).run
39
- rescue ArgumentError
36
+ TextToNoise::CommandLine.new( mapping_files, options ).run
37
+ rescue ArgumentError => e
40
38
  $stderr.puts arg_parser
41
39
  $stderr.puts <<-EOS
42
40
 
43
41
  ERROR!
44
42
 
45
- Could not locate a noise configuration.
46
- Specify a configuration with the -c option.
43
+ Error parsing configuration file, or configuration missing.
44
+ \t#{e}
47
45
 
48
46
  Try this one if you're processing a Rails log:
49
47
 
@@ -64,7 +62,7 @@ Copy one of those into a file and pass it along to text_to_noise.
64
62
  For example:
65
63
 
66
64
  echo 'match /sshd.*Accepted/ => %w[rooster hawk chicken crow]' > ssh.sounds.rb
67
- tail -f /var/log/secure.log | text_to_noise -c ssh.sounds.rb
65
+ tail -f /var/log/secure.log | text_to_noise ssh.sounds.rb
68
66
 
69
67
  Still having problems?
70
68
  Try logging an issue at https://github.com/tobytripp/text_to_noise/issues
@@ -8,9 +8,6 @@ Feature: Running text_to_noise
8
8
 
9
9
  Then the output should contain:
10
10
  """
11
- Could not locate a noise configuration.
12
- Specify a configuration with the -c option.
13
-
14
11
  Try this one if you're processing a Rails log:
15
12
 
16
13
  match /User Load/ => "nightingale"
@@ -15,7 +15,7 @@ Feature: Mapping input lines to sounds for playback
15
15
 
16
16
  """
17
17
 
18
- When I run `text_to_noise --config sound_mapping.rb --file stuff.log --mute`
18
+ When I run `text_to_noise sound_mapping.rb --file stuff.log --mute`
19
19
 
20
20
  Then the output should contain:
21
21
  """
@@ -25,7 +25,8 @@ Feature: Mapping input lines to sounds for playback
25
25
  Scenario: Using a Hash to specify mappings
26
26
  Given a file named "sound_mapping.rb" with:
27
27
  """
28
- map /caw/ => "crow", /bakawk/ => "chicken"
28
+ map /caw/ => "crow"
29
+ map /bakawk/ => "chicken"
29
30
  """
30
31
 
31
32
  And a file named "input.log" with:
@@ -34,7 +35,7 @@ Feature: Mapping input lines to sounds for playback
34
35
  bakawk!
35
36
  """
36
37
 
37
- When I run `text_to_noise -c sound_mapping.rb -f input.log -m`
38
+ When I run `text_to_noise sound_mapping.rb -f input.log -m`
38
39
 
39
40
  Then the output should contain "Playing crow.wav"
40
41
  And the output should contain "Playing chicken.wav"
@@ -58,7 +59,7 @@ Feature: Mapping input lines to sounds for playback
58
59
  User Load (7.1ms)
59
60
  """
60
61
 
61
- When I run `text_to_noise -c sound_mapping.rb -f input.log -m`
62
+ When I run `text_to_noise sound_mapping.rb -f input.log -m`
62
63
 
63
64
  Then the output should contain "Playing slow_query.wav"
64
65
  And the output should not contain "Playing slow_request.wav"
@@ -66,7 +67,8 @@ Feature: Mapping input lines to sounds for playback
66
67
  Scenario: Inputs that match multiple rules should fire all sounds
67
68
  Given a file named "sound_mapping.rb" with:
68
69
  """
69
- map /caw/ => "crow", /bakawk/ => "chicken"
70
+ map /caw/ => "crow"
71
+ map /bakawk/ => "chicken"
70
72
  """
71
73
 
72
74
  And a file named "input.log" with:
@@ -74,14 +76,13 @@ Feature: Mapping input lines to sounds for playback
74
76
  caw bakawk!
75
77
  """
76
78
 
77
- When I run `text_to_noise -c sound_mapping.rb -f input.log -m`
79
+ When I run `text_to_noise sound_mapping.rb -f input.log -m`
78
80
 
79
81
  Then the output should contain "Playing crow.wav"
80
82
  And the output should contain "Playing chicken.wav"
81
83
 
82
- @wip
83
84
  Scenario: Throttling a match
84
- Given a file named "sound_mapping" with:
85
+ Given a file named "sound_mapping.rb" with:
85
86
  """
86
87
  map /Rendered/ => 'crickets', :every => 5
87
88
  map( /page/ ).to( 'crickets' ).every( 5 )
@@ -103,10 +104,49 @@ Feature: Mapping input lines to sounds for playback
103
104
  Rendered a page
104
105
  """
105
106
 
106
- When I run `text_to_noise -c sound_mapping -f input.short.log -m`
107
+ When I run `text_to_noise sound_mapping.rb -f input.short.log -m`
107
108
 
108
109
  Then the output should not contain "Playing crickets.wav"
109
110
 
110
- When I run `text_to_noise -c sound_mapping -f input.long.log -m`
111
+ When I run `text_to_noise sound_mapping.rb -f input.long.log -m`
111
112
 
112
113
  Then the output should contain "Playing crickets.wav"
114
+
115
+ Scenario: Throttling with a Proc
116
+ Given a file named "sound_mapping" with:
117
+ """
118
+ map( /Rendered (\w+) page/ ).to( 'frogs' ).when { |md| md[1] == 'A' }
119
+ map( /Rendered (\w+) page/ ).to( 'crickets' ).when { |md| md[1] == 'B' }
120
+ """
121
+
122
+ And a file named "input.log" with:
123
+ """
124
+ Rendered A page
125
+ """
126
+
127
+ When I run `text_to_noise sound_mapping -f input.log -m`
128
+
129
+ Then the output should not contain "Playing crickets.wav"
130
+ But the output should contain "Playing frogs.wav"
131
+
132
+ Scenario: Adding sound directories
133
+ Given a file named "sound_mapping" with:
134
+ """
135
+ sound_path 'other_sounds'
136
+ map /Rendered/ => 'blurp'
137
+ """
138
+
139
+ And a directory named "other_sounds"
140
+ And an empty file named "blurp.wav"
141
+
142
+ And a file named "input.log" with:
143
+ """
144
+ Rendered a page
145
+ """
146
+
147
+ When I run `text_to_noise sound_mapping -f input.log -m`
148
+
149
+ Then the output should contain "Playing blurp.wav"
150
+
151
+ @wip
152
+ Scenario: Set volume for a sound
@@ -3,3 +3,6 @@ lib = File.expand_path( '../../../lib/', __FILE__ )
3
3
  $:.unshift lib unless $:.include?( lib )
4
4
 
5
5
  require 'text_to_noise'
6
+
7
+ TextToNoise.logger = Logger.new "log/cucumber.log"
8
+ TextToNoise.logger.level = Logger::DEBUG
@@ -7,20 +7,23 @@ module TextToNoise
7
7
 
8
8
  DEFAULT_FILE_DELAY = 100
9
9
 
10
- def initialize( options={} )
10
+ def initialize( mapping_configurations, options={} )
11
11
  @options = {
12
12
  :input => $stdin
13
13
  }.merge options
14
14
 
15
- raise ArgumentError, "No configuration file provided." unless @options[:config]
15
+ configs = Array === mapping_configurations ? mapping_configurations : [mapping_configurations]
16
+
17
+ raise ArgumentError, "No configuration file provided." if configs.empty?
18
+
19
+ @mapping = Router.parse File.read( configs.first )
16
20
 
17
- @mapping = Mapper.parse File.read( @options[:config] )
18
21
  TextToNoise.player = self.player
19
22
  TextToNoise.throttle_delay = @options[:throttle] if @options[:throttle]
20
23
  TextToNoise.throttle_delay = @options[:throttle] || DEFAULT_FILE_DELAY if @options[:input] != $stdin
21
- TextToNoise.logger.level = Logger::DEBUG if @options[:debug]
24
+ TextToNoise.logger.level = Logger::DEBUG if @options[:debug]
22
25
  rescue Errno::ENOENT => e
23
- raise ArgumentError, "Could not locate configuration file: '#{@options[:config]}'"
26
+ raise ArgumentError, "Could not locate configuration file: '#{configs.first}' (#{e})"
24
27
  end
25
28
 
26
29
  def run
@@ -0,0 +1,24 @@
1
+ module TextToNoise
2
+ class IterationMappingCondition
3
+ attr_accessor :count
4
+
5
+ def initialize( count )
6
+ self.count = count
7
+ @iteration = 0
8
+ end
9
+
10
+ def play?( match_data=nil )
11
+ @iteration += 1
12
+ count == 1 || (@iteration % count == 0)
13
+ end
14
+ alias_method :call, :play?
15
+
16
+ def count=( new_count )
17
+ if new_count > 0
18
+ @count = new_count
19
+ else
20
+ @count = 1
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,89 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TextToNoise
3
+ class NoiseMapping
4
+ include Logging
5
+ attr_accessor :targets, :matcher_conditions
6
+
7
+ def initialize( expression_or_map, &block )
8
+ debug "Parsing expression: #{expression_or_map.inspect}"
9
+
10
+ @matcher_conditions = []
11
+ @regex = nil
12
+
13
+ case expression_or_map
14
+ when Regexp
15
+ @regex = expression_or_map
16
+ when Hash
17
+ expression_or_map.each do |k,v|
18
+ case k
19
+ when Regexp
20
+ @regex = k
21
+ self.to v
22
+ else
23
+ self.send k.to_sym, v
24
+ end
25
+ end
26
+ else
27
+ raise ArgumentError, "Unrecognized Mapping configuration: #{expression_or_map.inspect}"
28
+ end
29
+
30
+ raise ArgumentError,
31
+ "Bad configuration line. Missing match expression in \"#{expression_or_map.inspect}\"" if @regex.nil?
32
+
33
+ matcher_conditions << block if block_given?
34
+ end
35
+
36
+ def ===( other )
37
+ match_data = @regex.match( other )
38
+ !match_data.nil? && play?( match_data )
39
+ end
40
+
41
+ def to( sound_or_sounds )
42
+ if sound_or_sounds.is_a? Array
43
+ sounds = sound_or_sounds
44
+ else
45
+ sounds = [sound_or_sounds]
46
+ end
47
+
48
+ sounds.each do |sound|
49
+ s = sound
50
+ s += ".wav" unless sound =~ /.wav$/
51
+ self.targets << Proc.new {
52
+ info "#{self.class.name} : #{@regex.inspect} -> #{sound}"
53
+ TextToNoise.player.play s
54
+ }
55
+ end
56
+
57
+ self
58
+ end
59
+
60
+ def every( iteration_count )
61
+ @matcher_conditions << IterationMappingCondition.new( iteration_count )
62
+ self
63
+ end
64
+
65
+ def when( &clause )
66
+ @matcher_conditions << clause
67
+ self
68
+ end
69
+
70
+ def call()
71
+ debug "Calling '#{@regex.inspect}' target…"
72
+ target.call
73
+ end
74
+
75
+ def targets() @targets ||= []; end
76
+ def target()
77
+ @i = -1 unless @i
78
+ @i = (@i + 1) % targets.size
79
+ self.targets[@i]
80
+ end
81
+
82
+ private
83
+
84
+ def play?( match_data )
85
+ return true if @matcher_conditions.empty?
86
+ @matcher_conditions.any? { |c| c.call match_data }
87
+ end
88
+ end
89
+ end
@@ -13,7 +13,7 @@ module TextToNoise
13
13
  self.class.load_rubygame
14
14
 
15
15
  Rubygame::Sound.autoload_dirs << SOUND_DIR
16
- themes = Dir.new(SOUND_DIR).entries.reject { |e| e =~ /[.]/ }
16
+ themes = Dir.new(SOUND_DIR).entries.reject { |e| e =~ /^[.]/ }
17
17
  Rubygame::Sound.autoload_dirs.concat themes.map { |t| File.join SOUND_DIR, t }
18
18
 
19
19
  @sounds = []
@@ -35,6 +35,10 @@ module TextToNoise
35
35
  not @sounds.empty?
36
36
  end
37
37
 
38
+ def sound_dirs()
39
+ Rubygame::Sound.autoload_dirs
40
+ end
41
+
38
42
  def available_sounds()
39
43
  Rubygame::Sound.autoload_dirs.map do |dir|
40
44
  Dir[ "#{dir}/*.wav" ].map { |f| File.basename f }
@@ -44,6 +48,9 @@ module TextToNoise
44
48
  def self.load_rubygame()
45
49
  old_verbose, $VERBOSE = $VERBOSE, nil
46
50
  old_stream, stream = $stdout.dup, $stdout
51
+
52
+ return if defined? Rubygame::Sound
53
+
47
54
  stream.reopen '/dev/null'
48
55
  stream.sync = true
49
56
 
@@ -1,5 +1,5 @@
1
1
  module TextToNoise
2
- class Mapper
2
+ class Router
3
3
  include Logging
4
4
  attr_accessor :mappings
5
5
 
@@ -22,18 +22,14 @@ module TextToNoise
22
22
  matches.map { |m| m.call }
23
23
  end
24
24
 
25
- protected
25
+ def sound_path( path )
26
+ TextToNoise.player.sound_dirs << path
27
+ end
26
28
 
27
29
  def match( expression, &block )
28
- if expression.kind_of?( Hash ) && expression.size > 1
29
- expression.each do |k,v|
30
- match k => v
31
- end
32
- else
33
- debug "Creating map for #{expression.inspect}"
34
- mappings << mapping = Mapping.new( expression, &block )
35
- mapping
36
- end
30
+ debug "Creating map for #{expression.inspect}"
31
+ mappings << mapping = NoiseMapping.new( expression, &block )
32
+ mapping
37
33
  end
38
34
  alias_method :map, :match
39
35
  end
@@ -1,3 +1,3 @@
1
1
  module TextToNoise
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -1,6 +1,14 @@
1
- # match /Rendered/ => %w(crickets canary), :every => 6
2
- # match /Rendering/ => "cardinal"
3
- match /User Load/ => %w"nightingale crickets canary"
4
- match /Processing/ => "crickets"
5
- match /SessionsController#new/ => "owl"
6
- match /404 Not Found/ => "hawk"
1
+ sound_path "tmp/sounds"
2
+
3
+ map /Rendered/ => %w(cardinal crickets canary), :every => 6
4
+ map /Processing/ => "crickets", :every => 4
5
+
6
+ map /User Load/ => %w"nightingale crickets canary"
7
+ map /SessionsController#new/ => "owl-short"
8
+
9
+ map /404 Not Found/ => "hawk"
10
+ map /RoutingError/ => "hawk"
11
+
12
+ map( /Completed in (\d+)ms/ ) { |match_data|
13
+ match_data[1].to_i > 500
14
+ }
@@ -4,7 +4,8 @@ lib = File.expand_path( '../lib/', __FILE__ )
4
4
  $:.unshift lib unless $:.include?( lib )
5
5
 
6
6
  require 'text_to_noise'
7
- TextToNoise.logger.level = Logger::WARN
7
+ TextToNoise.logger = Logger.new "log/test.log"
8
+ TextToNoise.logger.level = Logger::DEBUG
8
9
 
9
10
  Rspec.configure do |c|
10
11
  c.mock_with :rspec
@@ -2,18 +2,18 @@ require 'spec_helper'
2
2
 
3
3
  module TextToNoise
4
4
  describe TextToNoise::CommandLine do
5
- let( :mapping ) { double( Mapping ) }
5
+ let( :mapping ) { double( NoiseMapping ) }
6
6
  let( :reader ) { double( LogReader, :call => nil ) }
7
7
 
8
8
  before :each do
9
- Mapper.stub!( :parse ).and_return mapping
9
+ Router.stub!( :parse ).and_return mapping
10
10
  LogReader.stub!( :new ).and_return reader
11
11
  File.stub!( :read ).with( "sound_map.rb" ).and_return "config"
12
12
  end
13
13
 
14
14
  describe "#initialize" do
15
15
  it "accepts an options object" do
16
- CommandLine.new( { :config => "sound_map.rb" } )
16
+ CommandLine.new "sound_map.rb", {}
17
17
  end
18
18
 
19
19
  it "throws an error if no config file is given" do
@@ -25,45 +25,45 @@ module TextToNoise
25
25
  it "raises an error if the config file cannot be found" do
26
26
  File.stub!( :read ).and_raise Errno::ENOENT
27
27
  lambda {
28
- CommandLine.new :config => "not_found"
28
+ CommandLine.new "not_found"
29
29
  }.should raise_error( ArgumentError )
30
30
  end
31
31
 
32
32
  context "when given a 'config' option" do
33
- it "instantiates a Mapping object with the specified configuration" do
33
+ it "instantiates a NoiseMapping object with the specified configuration" do
34
34
  File.should_receive( :read ).with( "sound_map.rb" ).and_return "config"
35
- Mapper.should_receive( :parse ).with( "config" )
35
+ Router.should_receive( :parse ).with( "config" )
36
36
 
37
- CommandLine.new :config => "sound_map.rb"
37
+ CommandLine.new "sound_map.rb"
38
38
  end
39
39
  end
40
40
 
41
41
  context "when given the 'mute' option" do
42
42
  it "sets the global Player to an instance of MutePlayer" do
43
43
  TextToNoise.should_receive( :player= ).with instance_of( MutePlayer )
44
- CommandLine.new :mute => true, :config => "sound_map.rb"
44
+ CommandLine.new "sound_map.rb", :mute => true
45
45
  end
46
46
  end
47
47
 
48
48
  context "when given the 'throttle' option" do
49
49
  it "sets the throttle_delay attribute on TextToNoise" do
50
50
  TextToNoise.should_receive( :throttle_delay= ).with 100
51
- CommandLine.new :config => "sound_map.rb", :throttle => 100
51
+ CommandLine.new "sound_map.rb", :throttle => 100
52
52
  end
53
53
  end
54
54
 
55
55
  context "when given a 'file' option" do
56
56
  it "sets a default throttle_delay" do
57
57
  TextToNoise.should_receive( :throttle_delay= ).with 100
58
- CommandLine.new :config => "sound_map.rb", :input => "sample.log"
58
+ CommandLine.new "sound_map.rb", :input => "sample.log"
59
59
  end
60
60
  end
61
61
  end
62
62
 
63
63
  describe "#run" do
64
- let( :options ) { Hash[:input, :io, :config, "sound_map.rb"] }
64
+ let( :options ) { Hash[:input, :io] }
65
65
 
66
- subject { CommandLine.new( options ) }
66
+ subject { CommandLine.new( "sound_map.rb", options ) }
67
67
 
68
68
 
69
69
  it "creates a new LogReader object" do
@@ -76,7 +76,7 @@ module TextToNoise
76
76
  subject.run
77
77
  end
78
78
 
79
- it "passes an instance of a Mapping to the LogReader" do
79
+ it "passes an instance of a NoiseMapping to the LogReader" do
80
80
  LogReader.should_receive( :new ).with( anything, mapping )
81
81
  subject.run
82
82
  end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe TextToNoise::IterationMappingCondition do
4
+ describe "construction" do
5
+ it "accepts a count" do
6
+ described_class.new 4
7
+ end
8
+ end
9
+
10
+ context "for value 1" do
11
+ subject { described_class.new 1 }
12
+
13
+ it "#play? returns true for all calls" do
14
+ 3.times do
15
+ subject.play?.should be_true
16
+ end
17
+ end
18
+ end
19
+
20
+ context "for value 2" do
21
+ subject { described_class.new 2 }
22
+
23
+ it "#play? returns true on every other call" do
24
+ subject.play?.should be_false
25
+ subject.play?.should be_true
26
+ subject.play?.should be_false
27
+ subject.play?.should be_true
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,177 @@
1
+ require 'spec_helper'
2
+
3
+ describe TextToNoise::NoiseMapping do
4
+
5
+ before { TextToNoise.player = double( TextToNoise::Player ) }
6
+
7
+ describe "#initialize" do
8
+ it "can accept a Hash" do
9
+ mapping = described_class.new /exp/ => "target"
10
+ mapping.target.should be_a( Proc )
11
+ end
12
+
13
+ it "allows the 'every' option to be specified in the Hash" do
14
+ mapping = described_class.new /exp/ => "target", :every => 3
15
+ mapping.matcher_conditions.should_not be_empty
16
+ end
17
+ end
18
+
19
+ describe "#===" do
20
+ context "when matching against a regex" do
21
+ subject { described_class.new /green/ }
22
+
23
+ it "returns true when the input matches its regex" do
24
+ subject.should === "green"
25
+ end
26
+
27
+ it "returns false when the input does not match its regex" do
28
+ subject.should_not === "blue"
29
+ end
30
+ end
31
+
32
+ context "when matching against a Proc" do
33
+ subject do
34
+ described_class.new( /green (\d+)/ ) { |match_data| match_data[1].to_i > 5 }
35
+ end
36
+
37
+ it "matches if the block returns true" do
38
+ should === "green 6"
39
+ end
40
+
41
+ it "does not match if the block returns false" do
42
+ should_not === "green 1"
43
+ end
44
+ end
45
+ end
46
+
47
+ describe "#to" do
48
+ subject { described_class.new /green/ }
49
+
50
+ it "sets the target of the mapping to a Proc" do
51
+ subject.to( "bar" )
52
+ subject.target.should be_a( Proc )
53
+ end
54
+
55
+ it "sets the target to call Player#play on #call" do
56
+ subject.to( "bar.wav" )
57
+ TextToNoise.player.should_receive( :play ).with "bar.wav"
58
+
59
+ subject.target.call
60
+ end
61
+
62
+ it "automatically appends .wav, if it's not present" do
63
+ subject.to( "bar" )
64
+ TextToNoise.player.should_receive( :play ).with "bar.wav"
65
+
66
+ subject.target.call
67
+ end
68
+
69
+ it "can accept a list of target files" do
70
+ subject.to ["foo", "bar", "baz"]
71
+ TextToNoise.player.should_receive( :play ).with "foo.wav"
72
+ TextToNoise.player.should_receive( :play ).with "bar.wav"
73
+ TextToNoise.player.should_receive( :play ).with "baz.wav"
74
+
75
+ subject.target.call
76
+ subject.target.call
77
+ subject.target.call
78
+ end
79
+
80
+ it "returns self" do
81
+ subject.to( "foo" ).should == subject
82
+ end
83
+ end
84
+
85
+ describe "#every" do
86
+ context "when passed the value '3'" do
87
+ subject { described_class.new( /green/ ).to( "red" ).every( 3 ) }
88
+
89
+ it "does not match immediately" do
90
+ subject.should_not === 'green'
91
+ end
92
+
93
+ it "only matches on the given iteration" do
94
+ subject.should_not === 'green'
95
+ subject.should_not === 'green'
96
+ subject.should === 'green'
97
+ subject.should_not === 'green'
98
+ subject.should_not === 'green'
99
+ end
100
+ end
101
+
102
+ context "when passed the value 1" do
103
+ subject { described_class.new( /green/ ).to( "red" ).every( 1 ) }
104
+
105
+ it "matches on every iteration" do
106
+ subject.should === 'green'
107
+ subject.should === 'green'
108
+ subject.should === 'green'
109
+ end
110
+ end
111
+
112
+ context "when passed the value 0" do
113
+ subject { described_class.new( /green/ ).to( "red" ).every( 0 ) }
114
+
115
+ it "matches on every iteration" do
116
+ subject.should === 'green'
117
+ subject.should === 'green'
118
+ subject.should === 'green'
119
+ end
120
+ end
121
+
122
+ context "when passed the value -1" do
123
+ subject { described_class.new( /green/ ).to( "red" ).every( 0 ) }
124
+
125
+ it "matches on every iteration" do
126
+ subject.should === 'green'
127
+ subject.should === 'green'
128
+ subject.should === 'green'
129
+ end
130
+ end
131
+
132
+ context "when called multiple times" do
133
+ subject do
134
+ described_class.new( /green/ ).to( "red" ).
135
+ every( 3 ).
136
+ every( 5 )
137
+ end
138
+
139
+ it "fires when any rule matches" do
140
+ TextToNoise.player.should_receive( :play ).exactly( 3 ).times
141
+ 8.times { subject.call if subject === "green" }
142
+ end
143
+ end
144
+ end
145
+
146
+ describe "#when" do
147
+ let( :player ) { TextToNoise.player }
148
+
149
+ context "given a Proc that returns true" do
150
+ subject { described_class.new( /blue/ ).to( "green" ).when { true } }
151
+
152
+ it "will match the given input" do
153
+ subject.should === "blue"
154
+ end
155
+ end
156
+
157
+ context "given a Proc that returns false" do
158
+ subject { described_class.new( /blue/ ).to( "green" ).when { false } }
159
+
160
+ it "does not match the input" do
161
+ subject.should_not === "blue"
162
+ end
163
+ end
164
+ end
165
+
166
+ describe "#call" do
167
+ subject do
168
+ described_class.new( /green/ ).tap do |mapping|
169
+ mapping.targets = [Proc.new { "called" }]
170
+ end
171
+ end
172
+
173
+ it "calls #call on its target" do
174
+ subject.call.should == "called"
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ module Rubygame
4
+ class Sound
5
+ class << self
6
+ attr_accessor :autoload_dirs
7
+
8
+ def []( sound_name )
9
+ end
10
+
11
+ def autoload_dirs()
12
+ @autoload_dirs ||= []
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ describe TextToNoise::Player do
19
+ describe "construction" do
20
+ it "adds the default folder to the autoload paths" do
21
+ described_class.new
22
+ Rubygame::Sound.autoload_dirs.should include( TextToNoise::Player::SOUND_DIR )
23
+ end
24
+ end
25
+
26
+ describe "#sound_dirs" do
27
+ it "delegates to the underlying rubygame attribute" do
28
+ subject.sound_dirs << "bar"
29
+ Rubygame::Sound.autoload_dirs.should include( "bar" )
30
+ end
31
+ end
32
+ end
@@ -1,15 +1,15 @@
1
1
  require 'spec_helper'
2
2
  module TextToNoise
3
- describe Mapper do
3
+ describe Router do
4
4
  it "reloads its configuration if it has changed"
5
5
 
6
6
  describe ".parse" do
7
- let( :mapping ) { double( Mapping, :to => nil ) }
7
+ let( :mapping ) { double( NoiseMapping, :to => nil ) }
8
8
 
9
9
  context "given a nil configuration" do
10
10
  it "raises an ArgumentError" do
11
11
  lambda {
12
- Mapper.parse nil
12
+ Router.parse nil
13
13
  }.should raise_error( ArgumentError )
14
14
  end
15
15
  end
@@ -17,7 +17,7 @@ module TextToNoise
17
17
  context "given a blank configuration" do
18
18
  it "raises an ArgumentError" do
19
19
  lambda {
20
- Mapper.parse " \t \n"
20
+ Router.parse " \t \n"
21
21
  }.should raise_error( ArgumentError )
22
22
  end
23
23
  end
@@ -26,30 +26,30 @@ module TextToNoise
26
26
  let( :config ) { "match( /brown/ ).to \"blue\"" }
27
27
 
28
28
  it "creates a Mapping object for the given configuration line" do
29
- Mapping.should_receive( :new ).with( /brown/ ).and_return mapping
30
- Mapper.parse config
29
+ NoiseMapping.should_receive( :new ).with( /brown/ ).and_return mapping
30
+ Router.parse config
31
31
  end
32
32
 
33
33
  it "configures the mapping" do
34
- Mapping.stub!( :new ).with( /brown/ ).and_return mapping
34
+ NoiseMapping.stub!( :new ).with( /brown/ ).and_return mapping
35
35
  mapping.should_receive( :to ).with( "blue" )
36
36
 
37
- Mapper.parse config
37
+ Router.parse config
38
38
  end
39
39
  end
40
40
 
41
41
  context "given a multiple line configuration" do
42
42
  let( :config ) { 'match( /brown/ ).to "blue"; map( /green/ ).to "orange"' }
43
- before { Mapping.stub!( :new ).and_return mapping }
43
+ before { NoiseMapping.stub!( :new ).and_return mapping }
44
44
 
45
45
  it "configures the second mapping in addition to the first" do
46
46
  mapping.should_receive( :to ).with "blue"
47
47
  mapping.should_receive( :to ).with "orange"
48
- Mapper.parse config
48
+ Router.parse config
49
49
  end
50
50
 
51
51
  it "stores the mappings" do
52
- Mapper.parse( config ).should have( 2 ).mappings
52
+ Router.parse( config ).should have( 2 ).mappings
53
53
  end
54
54
  end
55
55
 
@@ -57,20 +57,20 @@ module TextToNoise
57
57
  let( :config ) { "match /brown/ => \"blue\"\n" }
58
58
 
59
59
  it "configures the mapping" do
60
- Mapping.should_receive( :new ).with( /brown/ => "blue" ).and_return mapping
61
- Mapper.parse config
60
+ NoiseMapping.should_receive( :new ).with( /brown/ => "blue" ).and_return mapping
61
+ Router.parse config
62
62
  end
63
63
  end
64
+ end
64
65
 
65
- context "given a hash-style configuration with multiple mappings" do
66
- let( :config ) { "match /brown/ => \"blue\", /green/ => \"red\"\n" }
66
+ describe "#sound_path" do
67
+ subject { described_class.new }
68
+ before { TextToNoise.player = double( TextToNoise::Player ) }
67
69
 
68
- it "configures both mappings" do
69
- Mapping.should_receive( :new ).with( /brown/ => "blue" ).and_return mapping
70
- Mapping.should_receive( :new ).with( /green/ => "red" ).and_return mapping
71
-
72
- Mapper.parse config
73
- end
70
+ it "adds the argument to the player's sound paths" do
71
+ paths = []
72
+ TextToNoise.player.should_receive( :sound_dirs ).and_return paths
73
+ subject.sound_path "foo"
74
74
  end
75
75
  end
76
76
 
@@ -79,7 +79,7 @@ module TextToNoise
79
79
  let( :green ) { /green/ }
80
80
  let( :blue2 ) { /blu/ }
81
81
 
82
- subject { Mapper.new.tap { |m| m.mappings = [blue, green, blue2] } }
82
+ subject { Router.new.tap { |m| m.mappings = [blue, green, blue2] } }
83
83
 
84
84
  it "iterates over its mappings comparing them to the input with #===" do
85
85
  blue.should_receive( :=== ).with( anything )
data/watchr.rb CHANGED
@@ -6,7 +6,9 @@
6
6
  #
7
7
  begin
8
8
  require "g"
9
+ puts "Growl loaded"
9
10
  rescue LoadError
11
+ puts "No growl library found"
10
12
  end
11
13
 
12
14
  def announce( message )
@@ -21,12 +23,7 @@ end
21
23
 
22
24
  def specs_matching( type, name )
23
25
  puts "looking for specs of #{name}"
24
- matching_specs = Dir["spec/**/*#{name}*_spec.rb"]
25
- if matching_specs.empty?
26
- $stderr.puts "No matching specs found! Did you NOT TEST THIS?!"
27
- else
28
- spec *matching_specs
29
- end
26
+ spec *Dir["spec/**/*#{name}*_spec.rb"]
30
27
  end
31
28
 
32
29
  def run_all_tests
@@ -37,16 +34,15 @@ end
37
34
  def execute( cmd )
38
35
  puts "> #{cmd}"
39
36
  system cmd
37
+ system 'date'
40
38
  end
41
39
 
42
40
  watch( '^spec/[^/]*/(.*)_spec\.rb' ) { |m| spec m[0] }
43
41
  watch( '^spec/spec_helper\.rb' ) { |m| execute "rake spec" }
44
42
  watch( '^spec/support/.*' ) { |m| execute "rake spec" }
45
- watch( '^lib/([^/]+)/(.*)\.rb' ) { |m| specs_matching m[1], m[2] }
43
+ watch( '^app/([^/]+)/(.*)\.rb' ) { |m| specs_matching m[1], m[2] }
44
+ watch( '^features/(.*)' ) { |m| execute "cucumber #{m[0]}" }
46
45
  watch( '^features/step_definitions/.*' ) { |m| execute "cucumber features" }
47
- watch( '^features/([^/]+\.feature)' ) { |m|
48
- execute "cucumber #{m[0]}" unless m[1].include? "step_definitions"
49
- }
50
46
 
51
47
  Signal.trap 'INT' do
52
48
  if @sent_an_int then
@@ -59,8 +55,3 @@ Signal.trap 'INT' do
59
55
  run_all_tests
60
56
  end
61
57
  end
62
-
63
- # Ctrl-\
64
- Signal.trap 'QUIT' do
65
- run_all_tests
66
- end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: text-to-noise
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.2
5
+ version: 0.3.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Toby Tripp
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-05-03 00:00:00 Z
14
+ date: 2011-05-22 00:00:00 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rubygame
@@ -83,12 +83,13 @@ files:
83
83
  - features/support/env.rb
84
84
  - lib/text_to_noise.rb
85
85
  - lib/text_to_noise/command_line.rb
86
+ - lib/text_to_noise/iteration_mapping_condition.rb
86
87
  - lib/text_to_noise/log_reader.rb
87
88
  - lib/text_to_noise/logging.rb
88
- - lib/text_to_noise/mapper.rb
89
- - lib/text_to_noise/mapping.rb
90
89
  - lib/text_to_noise/mute_player.rb
90
+ - lib/text_to_noise/noise_mapping.rb
91
91
  - lib/text_to_noise/player.rb
92
+ - lib/text_to_noise/router.rb
92
93
  - lib/text_to_noise/version.rb
93
94
  - sample.sounds.rb
94
95
  - sounds/birds/australian_frogmouth.wav
@@ -108,6 +109,7 @@ files:
108
109
  - sounds/birds/mexican_red_parrot.wav
109
110
  - sounds/birds/mockingbird.wav
110
111
  - sounds/birds/nightingale.wav
112
+ - sounds/birds/owl-short.wav
111
113
  - sounds/birds/owl.wav
112
114
  - sounds/birds/peacock.wav
113
115
  - sounds/birds/pigeons.wav
@@ -119,9 +121,11 @@ files:
119
121
  - spec/spec.opts
120
122
  - spec/spec_helper.rb
121
123
  - spec/text_to_noise/command_line_spec.rb
124
+ - spec/text_to_noise/iteration_mapping_condition_spec.rb
122
125
  - spec/text_to_noise/log_reader_spec.rb
123
- - spec/text_to_noise/mapper_spec.rb
124
- - spec/text_to_noise/mapping_spec.rb
126
+ - spec/text_to_noise/noise_mapping_spec.rb
127
+ - spec/text_to_noise/player_spec.rb
128
+ - spec/text_to_noise/router_spec.rb
125
129
  - spec/text_to_noise/sound_map.rb
126
130
  - ssh.sounds.rb
127
131
  - text_to_noise.gemspec
@@ -162,7 +166,9 @@ test_files:
162
166
  - spec/spec.opts
163
167
  - spec/spec_helper.rb
164
168
  - spec/text_to_noise/command_line_spec.rb
169
+ - spec/text_to_noise/iteration_mapping_condition_spec.rb
165
170
  - spec/text_to_noise/log_reader_spec.rb
166
- - spec/text_to_noise/mapper_spec.rb
167
- - spec/text_to_noise/mapping_spec.rb
171
+ - spec/text_to_noise/noise_mapping_spec.rb
172
+ - spec/text_to_noise/player_spec.rb
173
+ - spec/text_to_noise/router_spec.rb
168
174
  - spec/text_to_noise/sound_map.rb
@@ -1,58 +0,0 @@
1
- module TextToNoise
2
- class Mapping
3
- include Logging
4
- attr_accessor :targets, :matcher_proc
5
-
6
- def initialize( expression_or_map, &block )
7
- case expression_or_map
8
- when Regexp
9
- @regex = expression_or_map
10
- when Hash
11
- @regex, target = expression_or_map.to_a.flatten
12
- self.to target
13
- else
14
- raise ArgumentError, "Unrecognized Mapping configuration: #{expression_or_map.inspect}"
15
- end
16
-
17
- @matcher_proc = block if block_given?
18
- end
19
-
20
- def ===( other )
21
- match_data = @regex.match( other )
22
- if matcher_proc
23
- match_data && matcher_proc.call( match_data )
24
- else
25
- not match_data.nil?
26
- end
27
- end
28
-
29
- def to( sound_or_sounds )
30
- if sound_or_sounds.is_a? Array
31
- sounds = sound_or_sounds
32
- else
33
- sounds = [sound_or_sounds]
34
- end
35
-
36
- sounds.each do |sound|
37
- s = sound
38
- s += ".wav" unless sound =~ /.wav$/
39
- self.targets << Proc.new {
40
- info "#{@regex.inspect} -> #{sound}"
41
- TextToNoise.player.play s
42
- }
43
- end
44
- end
45
-
46
- def call()
47
- debug "Calling '#{@regex.inspect}' target..."
48
- target.call
49
- end
50
-
51
- def targets() @targets ||= []; end
52
- def target()
53
- @i = -1 unless @i
54
- @i = (@i + 1) % targets.size
55
- self.targets[@i]
56
- end
57
- end
58
- end
@@ -1,91 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe TextToNoise::Mapping do
4
- describe "#initialize" do
5
- it "can accept a Hash" do
6
- mapping = described_class.new /exp/ => "target"
7
- mapping.target.should be_a( Proc )
8
- end
9
-
10
- it "stores a passed block for use in later matching" do
11
- mapping = described_class.new( /exp/ => "target" ) { |md| true }
12
- mapping.matcher_proc.should be_a( Proc )
13
- end
14
- end
15
-
16
- describe "#===" do
17
- context "when matching against a regex" do
18
- subject { described_class.new /green/ }
19
-
20
- it "returns true when the input matches its regex" do
21
- subject.should === "green"
22
- end
23
-
24
- it "returns false when the input does not match its regex" do
25
- subject.should_not === "blue"
26
- end
27
- end
28
-
29
- context "when matching against a Proc" do
30
- subject do
31
- described_class.new( /green (\d+)/ ) { |match_data| match_data[1].to_i > 5 }
32
- end
33
-
34
- it "matches if the block returns true" do
35
- should === "green 6"
36
- end
37
-
38
- it "does not match if the block returns false" do
39
- should_not === "green 1"
40
- end
41
- end
42
- end
43
-
44
- describe "#to" do
45
- subject { described_class.new /green/ }
46
-
47
- before { TextToNoise.player = double( TextToNoise::Player ) }
48
-
49
- it "sets the target of the mapping to a Proc" do
50
- subject.to( "bar" )
51
- subject.target.should be_a( Proc )
52
- end
53
-
54
- it "sets the target to call Player#play on #call" do
55
- subject.to( "bar.wav" )
56
- TextToNoise.player.should_receive( :play ).with "bar.wav"
57
-
58
- subject.target.call
59
- end
60
-
61
- it "automatically appends .wav, if it's not present" do
62
- subject.to( "bar" )
63
- TextToNoise.player.should_receive( :play ).with "bar.wav"
64
-
65
- subject.target.call
66
- end
67
-
68
- it "can accept a list of target files" do
69
- subject.to ["foo", "bar", "baz"]
70
- TextToNoise.player.should_receive( :play ).with "foo.wav"
71
- TextToNoise.player.should_receive( :play ).with "bar.wav"
72
- TextToNoise.player.should_receive( :play ).with "baz.wav"
73
-
74
- subject.target.call
75
- subject.target.call
76
- subject.target.call
77
- end
78
- end
79
-
80
- describe "#call" do
81
- subject do
82
- described_class.new( /green/ ).tap do |mapping|
83
- mapping.targets = [Proc.new { "called" }]
84
- end
85
- end
86
-
87
- it "calls #call on its target" do
88
- subject.call.should == "called"
89
- end
90
- end
91
- end