nyancat 0.1.0 → 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 (3) hide show
  1. data/bin/nyancat +37 -1
  2. data/lib/nyancat.rb +109 -40
  3. metadata +5 -5
@@ -36,6 +36,8 @@ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
36
36
  require 'nyancat'
37
37
  require 'optparse'
38
38
 
39
+ port = 23
40
+ telnet = false
39
41
  options = {}
40
42
  OptionParser.new do |opts|
41
43
  opts.banner = "Usage: nyancat [options]"
@@ -46,6 +48,40 @@ OptionParser.new do |opts|
46
48
  opts.on("-f", "--flavour FLAVOUR", "Available flavours: #{NyanCat.flavours.join(', ')}") do |f|
47
49
  options[:flavour] = f
48
50
  end
51
+ opts.on("-n", "--notime", "Don't show the time nyaned") do |n|
52
+ options[:hide_time] = n
53
+ end
54
+ opts.on("-l", "--listen [PORT]", "Run telnet server on PORT (default 21)") do |p|
55
+ telnet = true
56
+ port = p || 23
57
+ end
58
+ opts.on("-t", "--timeout SECONDS", "Timeout after SECONDS") do |t|
59
+ options[:timeout] = t.to_i
60
+ end
49
61
  end.parse!
50
62
 
51
- NyanCat.nyancat(options)
63
+ if telnet
64
+ # Start a new server listening on specified port
65
+ server = NyanCat::NyanServer.new(port, "::", options)
66
+ server.audit = true
67
+ server.start
68
+ server.join
69
+ else
70
+ stdout = IO.new STDOUT.fileno
71
+
72
+ # Get TTY size
73
+ options[:width], options[:height] = `stty size`.split.map { |x| x.to_i }.reverse
74
+
75
+ begin
76
+ n = NyanCat::NyanCat.new(stdout, options)
77
+ n.run
78
+ rescue SignalException => e
79
+ # Do nothing, exit gracefully
80
+ rescue Exception => e
81
+ puts "Oops, something went wrong..."
82
+ raise e
83
+ end
84
+ end
85
+
86
+
87
+
@@ -31,6 +31,8 @@
31
31
  # WITH THE SOFTWARE.
32
32
 
33
33
  require 'yaml'
34
+ require 'gserver'
35
+ require 'timeout'
34
36
 
35
37
  module NyanCat
36
38
  OUTPUT_CHAR = " "
@@ -39,58 +41,125 @@ module NyanCat
39
41
  return Dir.entries(File.expand_path("../nyancat/", __FILE__)).select { |entry| !(entry =='.' || entry == '..') }
40
42
  end
41
43
 
42
- def self.nyancat(options = {})
43
- flavour = options[:flavour] || 'original'
44
- mute = options[:mute] || false
44
+ class NyanCat
45
+ def initialize(io, options)
46
+ @running = false
47
+ @io = io
48
+ @term_width = options[:width] || 80
49
+ @term_height = options[:height] || 24
50
+ @mute = options[:mute] || false
51
+ @hide_time = options[:hide_time] || false
45
52
 
46
- frames = YAML.load_file(File.expand_path("../nyancat/#{flavour}/frames.yml", __FILE__))
47
- palette = YAML.load_file(File.expand_path("../nyancat/#{flavour}/palette.yml", __FILE__))
48
- audio = File.expand_path("../nyancat/#{flavour}/audio.mp3", __FILE__)
53
+ flavour = options[:flavour] || 'original'
54
+ frames = YAML.load_file(File.expand_path("../nyancat/#{flavour}/frames.yml", __FILE__))
55
+ palette = YAML.load_file(File.expand_path("../nyancat/#{flavour}/palette.yml", __FILE__))
49
56
 
50
- # Get TTY size
51
- term_width, term_height = `stty size`.split.map { |x| x.to_i }.reverse
57
+ @audio = File.expand_path("../nyancat/#{flavour}/audio.mp3", __FILE__)
52
58
 
53
- # Calculate the width in terms of the output char
54
- term_width = term_width / OUTPUT_CHAR.length
59
+ # Calculate the width in terms of the output char
60
+ term_width = @term_width / OUTPUT_CHAR.length
61
+ term_height = @term_height
55
62
 
56
- min_row = 0
57
- max_row = frames[0].length
63
+ min_row = 0
64
+ max_row = frames[0].length
58
65
 
59
- min_col = 0
60
- max_col = frames[0][0].length
66
+ min_col = 0
67
+ max_col = frames[0][0].length
61
68
 
62
- min_row = (max_row - term_height) / 2 if max_row > term_height
63
- max_row = min_row + term_height if max_row > term_height
69
+ min_row = (max_row - term_height) / 2 if max_row > term_height
70
+ max_row = min_row + term_height if max_row > term_height
64
71
 
65
- min_col = (max_col - term_width) / 2 if max_col > term_width
66
- max_col = min_col + term_width if max_col > term_width
72
+ min_col = (max_col - term_width) / 2 if max_col > term_width
73
+ max_col = min_col + term_width if max_col > term_width
67
74
 
68
- frames = frames.map do |frame|
69
- frame[min_row...max_row].map do |line|
70
- line.chars.to_a[min_col...max_col].map do |c|
71
- "\033[48;5;%dm%s" % [palette[c], OUTPUT_CHAR]
72
- end.join + "\033[m\n"
73
- end.join + "\033[H"
75
+ # Calculate the final animation width
76
+ @anim_width = (max_col - min_col) * OUTPUT_CHAR.length
77
+
78
+ # Precompute frames
79
+ @frames = frames.map do |frame|
80
+ frame[min_row...max_row].map do |line|
81
+ line.chars.to_a[min_col...max_col].map do |c|
82
+ "\033[48;5;%dm%s" % [palette[c], OUTPUT_CHAR]
83
+ end.join + "\033[m\n"
84
+ end
85
+ end
74
86
  end
75
87
 
76
- audio_thread = Thread.new { IO.popen("mpg123 -loop 0 -q #{audio} > /dev/null 2>&1") } unless mute
77
-
78
- start_time = Time.now
79
- printf("\033[H\033[2J\033[?25l")
80
- begin
81
- loop do
82
- frames.each do |frame|
83
- print frame
84
- sleep(0.09)
88
+ def run()
89
+ @running = true
90
+
91
+ begin
92
+ # Initialise term
93
+ @io.printf("\033[H\033[2J\033[?25l")
94
+
95
+ # Get start time
96
+ start_time = Time.now()
97
+
98
+ # Play audio
99
+ audio_t = Thread.new { IO.popen("mpg123 -loop 0 -q #{@audio} > /dev/null 2>&1") } unless @mute || nil
100
+
101
+ while @running
102
+ @frames.each do |frame|
103
+ # Print the next frame
104
+ @io.puts frame
105
+
106
+ # Print the time so far
107
+ unless @hide_time
108
+ time = "You have nyaned for %0.0f seconds!" % [Time.now() - start_time]
109
+ time = time.center(@anim_width)
110
+ @io.printf("\033[1;37;17m%s", time)
111
+ end
112
+
113
+ # Reset the frame and sleep
114
+ @io.printf("\033[H")
115
+ sleep(0.09)
116
+ end
85
117
  end
118
+
119
+ ensure
120
+ # Ensure the audio thread is killed, if it exists
121
+ audio_t.kill unless audio_t.nil?
122
+ stop
123
+ reset
124
+ end
125
+ end
126
+
127
+ def stop()
128
+ @running = false
129
+ end
130
+
131
+ def reset()
132
+ begin
133
+ @io.puts("\033[0m\033c")
134
+ rescue Errno::EPIPE => e
135
+ # We failed to reset the TERM, IO stream is gone
86
136
  end
87
- rescue SignalException => e
88
- printf("\033c\033c")
89
- printf("YOU NYANED FOR %4.2f SECONDS\n", Time.now - start_time)
90
- rescue Exception => e
91
- printf("\033c")
92
- puts "Oops, something went wrong..."
93
- raise e
94
137
  end
95
138
  end
139
+
140
+ class NyanServer < GServer
141
+ def initialize(port, address, options = {})
142
+ @options = options
143
+ @options[:mute] = true
144
+ @timeout = @options[:timeout]
145
+ super(port, address)
146
+ end
147
+
148
+ def serve(io)
149
+ n = NyanCat.new(io, @options)
150
+ begin
151
+ # run the animation thread
152
+ t = Thread.new(n) { |nyan| nyan.run() }
153
+
154
+ # block until any input is received or timeout is reached, then die
155
+ Timeout::timeout(@timeout) { io.readline() }
156
+ rescue Exception => e
157
+ log("Client error: #{e}")
158
+ ensure
159
+ n.stop
160
+ t.join
161
+ end
162
+ end
163
+ end
164
+
96
165
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nyancat
3
3
  version: !ruby/object:Gem::Version
4
+ version: 0.2.0
4
5
  prerelease:
5
- version: 0.1.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ben Arblaster
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-01 00:00:00.000000000 Z
12
+ date: 2013-02-01 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A Ruby port of Kevin Lange's nyancat
15
15
  email: ben@andatche.com
@@ -30,20 +30,20 @@ rdoc_options: []
30
30
  require_paths:
31
31
  - lib
32
32
  required_ruby_version: !ruby/object:Gem::Requirement
33
+ none: false
33
34
  requirements:
34
35
  - - ! '>='
35
36
  - !ruby/object:Gem::Version
36
37
  version: '0'
37
- none: false
38
38
  required_rubygems_version: !ruby/object:Gem::Requirement
39
+ none: false
39
40
  requirements:
40
41
  - - ! '>='
41
42
  - !ruby/object:Gem::Version
42
43
  version: '0'
43
- none: false
44
44
  requirements: []
45
45
  rubyforge_project:
46
- rubygems_version: 1.8.23
46
+ rubygems_version: 1.8.25
47
47
  signing_key:
48
48
  specification_version: 3
49
49
  summary: nyancat on your terminal