nyan 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ .rvmrc
4
+ Gemfile.lock
5
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in nyan_formatter.gemspec
4
+ gemspec
@@ -0,0 +1,6 @@
1
+ guard 'rspec', :version => 2 do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
@@ -0,0 +1,80 @@
1
+ Nyan ![travis-ci](https://secure.travis-ci.org/textgoeshere/nyan.png)
2
+ ==================
3
+
4
+ Your favourite aging meme is reheated as an RSpec custom formatter.
5
+
6
+ For entertainment purposes only.
7
+
8
+ FAQ
9
+ ---
10
+
11
+ * Didn't this meme jump the shark, like, ages ago?
12
+
13
+ Yes.
14
+
15
+ * It's got no tail
16
+
17
+ Look closer.
18
+
19
+ * It's got no feet!
20
+
21
+ LOOK CLOSER.
22
+
23
+ * It's really slow
24
+
25
+ Write faster specs.
26
+
27
+ * It's still really slow
28
+
29
+ Send me a pull request where the animation runs in a separate thread.
30
+
31
+ * The colours are all wrong
32
+
33
+ Probably need a new graphics card or something.
34
+
35
+ Requirements
36
+ ------------
37
+
38
+ * RSpec 2 (tested against RSpec 2.6)
39
+
40
+ Install
41
+ -------
42
+
43
+ Add to your `Gemfile` (usually inside your `:test` group):
44
+
45
+ gem "nyan"
46
+
47
+ Alternatively install directly:
48
+
49
+ $ gem install nyan
50
+
51
+ Usage
52
+ -----
53
+
54
+ $ rspec spec -f Nyan::Formatter
55
+
56
+ Or if you want the joy of Nyan without running specs, use the binary:
57
+
58
+ $ nyan
59
+
60
+ Your terminal should be at least 180 columns x 50 rows.
61
+
62
+ Development
63
+ -----------
64
+
65
+ * Source hosted at [GitHub](https://github.com/kapoq/nyan)
66
+ * Report issues/Questions/Feature requests on [GitHub Issues](https://github.com/kapoq/nyan)
67
+ * CI at [Travis](http://travis-ci.org/#!/textgoeshere/nyan)
68
+
69
+ Pull requests are very welcome! Make sure your patches are well tested. Please create a topic branch for every separate change
70
+ you make.
71
+
72
+ Testing
73
+ -------
74
+
75
+ $ rake
76
+
77
+ Author
78
+ ------
79
+
80
+ [Dave Nolan](https://github.com/textgoeshere)
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ nyan_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(nyan_dir) unless $LOAD_PATH.include?(nyan_dir)
4
+ require "nyan"
5
+
6
+ print cls
7
+ flight = Nyan::Flight.new
8
+ loop do
9
+ flight.next!
10
+ end
11
+
@@ -0,0 +1,20 @@
1
+ require "nyan/version"
2
+
3
+ require "nyan/colour"
4
+ require "nyan/shape"
5
+ require "nyan/sprite"
6
+ require "nyan/stage"
7
+
8
+ require "nyan/flight"
9
+
10
+ module Nyan
11
+ BLOCK = "\u2588"
12
+ SPACE = "\x20"
13
+ NEWLINE = "\n"
14
+
15
+ require "nyan/sprites/rainbow"
16
+ require "nyan/sprites/cat_head"
17
+ require "nyan/sprites/pop_tart"
18
+ require "nyan/sprites/tail"
19
+ require "nyan/sprites/star"
20
+ end
@@ -0,0 +1,27 @@
1
+ require "ansi"
2
+ include ANSI::Code
3
+
4
+ module Nyan
5
+ module Colour
6
+ MAP = {
7
+ "#" => "#{bright}#{black}",
8
+ "b" => "#{dark}#{black}",
9
+ "R" => "#{bright}#{magenta}",
10
+ "p" => "#{dark}#{magenta}",
11
+ "2" => "#{bright}#{yellow}",
12
+ "`" => "#{dark}#{yellow}",
13
+ "o" => "#{bright}#{white}",
14
+ "_" => "#{bright}#{white}",
15
+ "." => "#{dark}#{white}",
16
+ "1" => "#{bright}#{red}",
17
+ "3" => "#{bright}#{green}",
18
+ "4" => "#{bright}#{blue}",
19
+ "5" => "#{bright}#{magenta}"
20
+ }
21
+
22
+ def self.colourize(char)
23
+ escape_codes = MAP.fetch(char, reset)
24
+ "#{escape_codes}#{Nyan::BLOCK}"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,51 @@
1
+ module Nyan
2
+ class Flight
3
+ def initialize
4
+ @stage = Stage.new
5
+
6
+ @rainbow = Sprite.new(:x => 0, :y => 17, :z => 1, :frames => Nyan::Rainbow.to_frames)
7
+
8
+ @cat_head = Sprite.new(:x => Nyan::Rainbow::TOTAL_LENGTH - 2,
9
+ :y => 17,
10
+ :z => 100,
11
+ :frames => Nyan::CatHead.to_frames,
12
+ :animation => Proc.new do
13
+ @initial_x ||= @x
14
+ @initial_y ||= @y
15
+ case offset = [@x == @initial_x && :initial || :offset, @y == @initial_y && :initial || :offset]
16
+ when [:initial, :initial] then @y -= 2
17
+ when [:initial, :offset] then @x += 2
18
+ when [:offset, :offset] then @y += 2
19
+ when [:offset, :initial] then @x -= 2
20
+ end
21
+ end)
22
+
23
+ @pop_tart = Sprite.new(:x => @cat_head.x - 20,
24
+ :y => @cat_head.y - 2,
25
+ :z => @cat_head.z - 1,
26
+ :frames => Nyan::PopTart.to_frames)
27
+
28
+ @stage.add_sprite(@rainbow)
29
+ @stage.add_sprite(@cat_head)
30
+ @stage.add_sprite(@pop_tart)
31
+ @tick_time = Time.now
32
+ end
33
+
34
+ def next!
35
+ if rand > 0.85
36
+ speed = rand > 0.5 ? 2 : 5
37
+ star = Sprite.new(:x => @stage.width,
38
+ :y => rand(@stage.height - 11),
39
+ :z => 0,
40
+ :speed => speed,
41
+ :frames => Nyan::Star.to_frames,
42
+ :frame_index => rand(Nyan::Star.to_frames.length - 1),
43
+ :animation => Proc.new { self.x -= @options[:speed] })
44
+ @stage.add_sprite(star)
45
+ end
46
+ @stage.play!
47
+ loop until Time.now - @tick_time >= 0.09
48
+ @tick_time = Time.now
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,44 @@
1
+ require 'rspec/core/formatters/base_text_formatter'
2
+ require 'nyan'
3
+
4
+ module Nyan
5
+ class Formatter < RSpec::Core::Formatters::BaseTextFormatter
6
+ def initialize(*args)
7
+ super
8
+ @nyan_flight = Nyan::Flight.new
9
+ @still_passing = true
10
+ print cls
11
+ puts "Awaiting Nyan..."
12
+ end
13
+
14
+ def example_passed(_)
15
+ @nyan_flight.next! if @still_passing
16
+ end
17
+
18
+ def example_failed(example)
19
+ super
20
+ @output.print cls
21
+ @output.print move(0,0)
22
+ @output.puts red("NO NYAN FOR YOU")
23
+ @still_passing = false
24
+ end
25
+
26
+ def dump_failures
27
+ return if failed_examples.empty?
28
+ output.puts
29
+ output.puts "Failures:"
30
+ failed_examples.each_with_index do |example, index|
31
+ output.puts
32
+ dump_pending_example_fixed(example, index) || dump_failure(example, index)
33
+ dump_backtrace(example)
34
+ end
35
+ end
36
+
37
+ def dump_backtrace(example)
38
+ format_backtrace(example.execution_result[:exception].backtrace, example).each do |backtrace_info|
39
+ output.puts cyan(" # #{backtrace_info}")
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,16 @@
1
+ module Nyan
2
+ module Shape
3
+ attr_accessor :top, :bottom, :left, :right
4
+
5
+ def outside?(other_shape)
6
+ (right < other_shape.left) or
7
+ (top > other_shape.bottom) or
8
+ (left > other_shape.right) or
9
+ (bottom < other_shape.top)
10
+ end
11
+
12
+ def inside?(other_shape)
13
+ !outside(other_shape)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,60 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Nyan
3
+ class Sprite
4
+ include Shape
5
+
6
+ attr_accessor :x, :y, :z, :frames, :frame_index
7
+ attr_reader :blk
8
+
9
+ def initialize(options = {}, &blk)
10
+ @options = options
11
+ self.x = @options.fetch(:x, 0)
12
+ self.y = @options.fetch(:y, 0)
13
+ self.z = @options.fetch(:z, 0)
14
+ self.frames = @options.fetch(:frames, [])
15
+ self.frame_index = @options.fetch(:frame_index, 0)
16
+ @blk = blk || @options[:animation]
17
+ end
18
+
19
+ def frame
20
+ frames[frame_index]
21
+ end
22
+
23
+ def lines
24
+ frame.lines
25
+ end
26
+
27
+ def animate!
28
+ self.frame_index = (self.frame_index + 1) % frames.length
29
+ self.instance_eval(&blk) if blk
30
+ end
31
+
32
+ def height
33
+ @height ||= frame.lines.count
34
+ end
35
+
36
+ def width
37
+ @width ||= frame.lines.map { |l| l.chomp.unansi.length }.max
38
+ end
39
+
40
+ def top
41
+ y
42
+ end
43
+
44
+ def bottom
45
+ y + height
46
+ end
47
+
48
+ def left
49
+ x
50
+ end
51
+
52
+ def right
53
+ x + width
54
+ end
55
+
56
+ def <=>(other)
57
+ z <=> other.z
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,26 @@
1
+ module Nyan
2
+ module CatHead
3
+ SHAPE =<<EOF
4
+ # #
5
+ #.### ###.#
6
+ #....## ##...#
7
+ #__....############...__#
8
+ ___...#..........#..___
9
+ #__.................__#
10
+ #.....................#
11
+ #....o#.......o#....#
12
+ #....##.......##....#
13
+ #........b.b........#
14
+ #.p.......b.......p.#
15
+ #.p.b....b....b.p.#
16
+ #...b....b....b...#
17
+ #....bbbb.bbbb....#
18
+ ###...........###
19
+ ###########
20
+ EOF
21
+
22
+ def self.to_frames
23
+ @frames ||= Array(SHAPE)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ module Nyan
2
+ module PopTart
3
+ SHAPE =<<-EOF
4
+ ooooooooooooooooooooooooooooo
5
+ o22222222222222222222222222222o
6
+ o222222ppppppppppppppppp22222222o
7
+ o22222ppppppRRRpppppppppppppppp222o
8
+ o22pppppppppRRRppppppppppppppppp22o
9
+ o22pppppRRRppRRRpppppppRRpppppppp222o
10
+ o222ppppRRRppppppppppppRppppppppp222o
11
+ o222pppppppppppppppppppRpppppppppp22o
12
+ o222ppppRRRppppppRRRppppppppppp222o
13
+ o222ppppRRRppppppRRRppppppppppp2222o
14
+ o22pppppppppppppppppppppppppppp22222o
15
+ o22ppppppppRRRpppppppppppppppppp2222o
16
+ o22ppppppppRRRppppppRRRppppppppp2222o
17
+ o22ppppppppRRRppppppRRRppppppppp2222o
18
+ o22pppppppppppppppppRRRpppppppppp222o
19
+ o222pppppppppppppppppppppppppppp2222o
20
+ o222222ppppppppppppppppp222222222222o
21
+ ooooooooooooooooooooooooooooooooooo
22
+ EOF
23
+
24
+ def self.to_frames
25
+ @fames ||= Array(SHAPE)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,45 @@
1
+ module Nyan
2
+ module Rainbow
3
+ BAND_HEIGHT = 3
4
+ BEND_LENGTH = 18
5
+ SECTIONS = 5
6
+
7
+ COLOURS = %w(1 2 3 4 5)
8
+ BLANK = ([Nyan::SPACE] * BEND_LENGTH).join
9
+
10
+ FRAME_HEIGHT = COLOURS.length * BAND_HEIGHT + 1
11
+ FRAME_WIDTH = SECTIONS * BEND_LENGTH
12
+
13
+ TOTAL_LENGTH = SECTIONS * BEND_LENGTH
14
+ TOTAL_HEIGHT = BAND_HEIGHT * COLOURS.length
15
+
16
+ SLICE = COLOURS.each_with_object([]) do |colour, slice|
17
+ BAND_HEIGHT.times do
18
+ slice << "#{colour}" * BEND_LENGTH
19
+ end
20
+ end
21
+
22
+ def self.frame(is_peak = true)
23
+ frame_rows = Array.new(FRAME_HEIGHT + 1) { String.new }
24
+
25
+ SECTIONS.times do
26
+ this_slice = SLICE.dup
27
+ FRAME_HEIGHT.times do |i|
28
+ this_row = if (is_peak && i == FRAME_HEIGHT - 1) or (!is_peak && i == 0)
29
+ BLANK
30
+ else
31
+ this_slice.shift
32
+ end
33
+ frame_rows[i] << this_row
34
+ end
35
+ is_peak = !is_peak
36
+ end
37
+
38
+ frame_rows.join(NEWLINE)
39
+ end
40
+
41
+ def self.to_frames
42
+ @frames ||= [frame(true), frame(false)]
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,81 @@
1
+ module Nyan
2
+ module Star
3
+ SHAPE_LIST =<<EOF
4
+ ...........
5
+ ...........
6
+ ...........
7
+ ...........
8
+ ...........
9
+ .....X.....
10
+ ...........
11
+ ...........
12
+ ...........
13
+ ...........
14
+ ...........
15
+ --
16
+ ...........
17
+ ...........
18
+ ...........
19
+ ...........
20
+ .....X.....
21
+ ....X.X....
22
+ .....X.....
23
+ ...........
24
+ ...........
25
+ ...........
26
+ ...........
27
+ --
28
+ ...........
29
+ ...........
30
+ ...........
31
+ .....X.....
32
+ .....X.....
33
+ ...XX.XX...
34
+ .....X.....
35
+ .....X.....
36
+ ...........
37
+ ...........
38
+ ...........
39
+ --
40
+ ...........
41
+ .....X.....
42
+ .....X.....
43
+ .....X.....
44
+ ...........
45
+ .XXX.X.XXX.
46
+ ...........
47
+ .....X.....
48
+ .....X.....
49
+ .....X.....
50
+ ...........
51
+ --
52
+ ...........
53
+ ....XXX....
54
+ ...X...X...
55
+ .X.......X.
56
+ X.........X
57
+ X.........X
58
+ X.........X
59
+ .X.......X.
60
+ ..X.....X..
61
+ ....XXX....
62
+ ...........
63
+ --
64
+ .....X.....
65
+ ...........
66
+ ...........
67
+ ...........
68
+ ...........
69
+ X.........X
70
+ ...........
71
+ ...........
72
+ ...........
73
+ ...........
74
+ .....X.....
75
+ EOF
76
+
77
+ def self.to_frames
78
+ @frames ||= SHAPE_LIST.gsub(/\./, SPACE).gsub(/X/, BLOCK).split(/--./m)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,27 @@
1
+ module Nyan
2
+ module Tail
3
+ SHAPE_LIST =<<-EOF
4
+ ..................
5
+ ..................
6
+ ..................
7
+ ..................
8
+ ..................
9
+ --
10
+ ..................
11
+ ..................
12
+ ..................
13
+ ..................
14
+ ..................
15
+ --
16
+ ..................
17
+ ..................
18
+ ..................
19
+ ..................
20
+ ..................
21
+ EOF
22
+
23
+ def self.to_frames
24
+ @frames ||= SHAPE_LIST.gsub(/\./, SPACE).gsub(/X/, BLOCK).split(/--./m)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,109 @@
1
+ module Nyan
2
+ class Stage
3
+ include Shape
4
+
5
+ SPACE = "\x20"
6
+ NOTHING = ""
7
+
8
+ attr_reader :output, :height, :width
9
+
10
+ def initialize(options = {})
11
+ @output = options.fetch(:output, $stdout)
12
+ @height = options.fetch(:height, ANSI::Terminal.terminal_height)
13
+ @width = options.fetch(:width, ANSI::Terminal.terminal_width)
14
+ @coloured = options.fetch(:coloured, true)
15
+ clear_buffer
16
+ end
17
+
18
+ def sprites
19
+ @sprites ||= []
20
+ end
21
+
22
+ def add_sprite(sprite)
23
+ self.sprites.push(sprite)
24
+ end
25
+
26
+ def remove_sprite(sprite)
27
+ self.sprites.delete(sprite)
28
+ end
29
+
30
+ def play!
31
+ render
32
+ animate!
33
+ clean!
34
+ end
35
+
36
+ def render
37
+ clear_buffer
38
+ sprites.sort.each { |s| write_to_buffer(s) }
39
+ print_buffer
40
+ end
41
+
42
+ def animate!
43
+ sprites.each { |s| s.animate! }
44
+ end
45
+
46
+ def clean!
47
+ sprites.delete_if { |s| s.outside?(self) }
48
+ end
49
+
50
+ def top
51
+ 0
52
+ end
53
+
54
+ def bottom
55
+ height - 1
56
+ end
57
+
58
+ def left
59
+ 0
60
+ end
61
+
62
+ def right
63
+ width - 1
64
+ end
65
+
66
+ def coloured?
67
+ @coloured
68
+ end
69
+
70
+ private
71
+
72
+ def clear_buffer
73
+ @buffer = Array.new(height) do
74
+ Array.new(width) do
75
+ { :char => SPACE, :colourized_char => SPACE }
76
+ end
77
+ end
78
+ end
79
+
80
+ def write_to_buffer(sprite)
81
+ sprite.lines.each_with_index do |line, i|
82
+ line_y = sprite.y + i
83
+ previous_colourized_char = nil
84
+ if line_y.between?(top, bottom)
85
+ line.chomp.chars.each_with_index do |char, j|
86
+ char_x = sprite.x + j
87
+ if char_x.between?(left, right) && char != Nyan::SPACE
88
+ colourized_char = Colour.colourize(char)
89
+ colourized_char = Nyan::BLOCK if colourized_char == previous_colourized_char
90
+ @buffer[line_y][char_x] = { :char => char, :colourized_char => colourized_char }
91
+ previous_colourized_char = colourized_char
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ def print_buffer
99
+ key = coloured? ? :colourized_char : :char
100
+ @buffer.each_with_index do |row, i|
101
+ output.print move(i, 0)
102
+ output.print clear_line
103
+ output.print reset
104
+ output.print row.map { |h| h[key] }.join
105
+ output.print "\n" unless i == bottom
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,3 @@
1
+ module Nyan
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "nyan/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "nyan"
7
+ s.version = Nyan::VERSION
8
+ s.authors = ["dave@kapoq.com"]
9
+ s.email = ["dave@kapoq.com"]
10
+ s.homepage = "https://github.com/kapoq/nyan_formatter"
11
+ s.summary = "Nyan Cat flies across your terminal while your RSpec specs run!"
12
+ s.description = "Your favourite aging meme is reheated as an RSpec custom formatter. For entertainment purposes only. WARNING: enterprise-ready"
13
+
14
+ s.add_dependency "ansi"
15
+ s.add_dependency "rspec"
16
+
17
+ s.add_development_dependency "guard-rspec"
18
+ s.add_development_dependency "rake"
19
+ if RUBY_PLATFORM =~ /linux/
20
+ s.add_development_dependency "rb-inotify"
21
+ s.add_development_dependency "libnotify"
22
+ end
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ s.require_paths = ["lib"]
28
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Nyan::Colour do
4
+ describe ".colourize" do
5
+ it "looks up the char in the map" do
6
+ Nyan::Colour::MAP.should_receive(:fetch).with("X", anything)
7
+ Nyan::Colour.colourize("X")
8
+ end
9
+
10
+ it "returns the escape code for the colour followed by a block char" do
11
+ Nyan::Colour::MAP.stub(:fetch => "__ESC__")
12
+ Nyan::Colour.colourize("X").should eql "__ESC__#{Nyan::BLOCK}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ class SimpleShape
4
+ include ::Nyan::Shape
5
+
6
+ def initialize
7
+ @top, @bottom, @left, @right = [0, 0, 0, 0]
8
+ end
9
+ end
10
+
11
+ describe Nyan::Shape do
12
+ let(:shape) { SimpleShape.new }
13
+
14
+ describe "#outside?" do
15
+ let(:other_shape) { SimpleShape.new }
16
+
17
+ it "is outside when its right edge is beyond the left edge of the other shape" do
18
+ shape.right = other_shape.left - 1
19
+ shape.should be_outside(other_shape)
20
+ end
21
+
22
+ it "is outside when its left edge is beyond the right edge of the other shape" do
23
+ shape.left = other_shape.right + 1
24
+ shape.should be_outside(other_shape)
25
+ end
26
+
27
+ it "is outside when its top edge is below the bottom edge of the other shape" do
28
+ shape.top = other_shape.bottom + 1
29
+ shape.should be_outside(other_shape)
30
+ end
31
+
32
+ it "is outside when its bottom edge is above the top edge of the other shape" do
33
+ shape.bottom = other_shape.top - 1
34
+ shape.should be_outside(other_shape)
35
+ end
36
+
37
+ it "is not outside when its edges are all within the edges of the other shape" do
38
+ shape.should_not be_outside(other_shape)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe Nyan::Sprite do
4
+ let(:output) { StringIO.new }
5
+ let(:sprite) { Nyan::Sprite.new }
6
+ let(:frame1) { double(:frame1) }
7
+ let(:frame2) { double(:frame2) }
8
+ let(:frames) { [frame1, frame2] }
9
+
10
+ describe "#initialize" do
11
+ it "accepts optional x, y, and frames parameters and sets its instance variables to their values" do
12
+ sprite = Nyan::Sprite.new(:x => 1, :y => 2, :z => 3, :frames => frames, :frame_index => 4)
13
+ sprite.x.should == 1
14
+ sprite.y.should == 2
15
+ sprite.z.should == 3
16
+ sprite.frame_index.should == 4
17
+ sprite.frames.should == frames
18
+ end
19
+
20
+ describe "defaults" do
21
+ it "x = 0" do
22
+ sprite.x.should == 0
23
+ end
24
+
25
+ it "y = 0" do
26
+ sprite.y.should == 0
27
+ end
28
+
29
+ it "z = 0" do
30
+ sprite.z.should == 0
31
+ end
32
+
33
+ it "frames is an empty array" do
34
+ sprite.frames.should == []
35
+ end
36
+
37
+ it "frame_index = 0" do
38
+ sprite.frame_index.should == 0
39
+ end
40
+ end
41
+
42
+ it "accepts an block which is executed each animation step" do
43
+ sprite = Nyan::Sprite.new(:frames => frames) do
44
+ self.x = 99
45
+ end
46
+ sprite.should_receive(:x=).with(99)
47
+ sprite.animate!
48
+ end
49
+
50
+ it "accepts a Proc as an optional animation parameter which is executed each animation step" do
51
+ sprite = Nyan::Sprite.new(:frames => frames, :animation => Proc.new { self.x = 99 })
52
+ sprite.should_receive(:x=).with(99)
53
+ sprite.animate!
54
+ end
55
+
56
+ it "has left at x" do
57
+ sprite.x = 99
58
+ sprite.left.should == 99
59
+ end
60
+
61
+ it "has right at x + width" do
62
+ sprite.x = 99
63
+ sprite.stub(:width => 99)
64
+ sprite.right.should == 198
65
+ end
66
+
67
+ it "has top at y" do
68
+ sprite.y = 77
69
+ sprite.top.should == 77
70
+ end
71
+
72
+ it "has bottom at y + height" do
73
+ sprite.y = 77
74
+ sprite.stub(:height => 99)
75
+ sprite.bottom.should == 176
76
+ end
77
+ end
78
+
79
+ describe "frames" do
80
+ before do
81
+ sprite.frames = frames
82
+ end
83
+
84
+ describe "#frames" do
85
+ it "returns array of frames" do
86
+ sprite.frames.should eql frames
87
+ end
88
+ end
89
+
90
+ describe "#frame" do
91
+ it "returns the current frame" do
92
+ sprite.frame.should eql frame1
93
+ end
94
+ end
95
+
96
+ describe "#animate!" do
97
+ it "sets current frame to the next frame, looping to the start when necessary" do
98
+ sprite.frame_index = 1
99
+ sprite.animate!
100
+ sprite.frame.should eql frame1
101
+ end
102
+ end
103
+ end
104
+
105
+ it "has a height equal to the number of lines in the frame" do
106
+ sprite.frames = ["1\n2\n3\n4"]
107
+ sprite.height.should == 4
108
+ end
109
+
110
+ it "has a width equal to the number of characters in widest line of the frame excluding line breaks" do
111
+ sprite.frames = ["1\n22\n333\n22\n22"]
112
+ sprite.width.should == 3
113
+ end
114
+
115
+ describe "#<=>" do
116
+ let(:a) { double("Sprite a") }
117
+ let(:b) { double("Sprite b") }
118
+
119
+ it "sorts by z" do
120
+ a.should_receive(:<=>).with(b)
121
+ a <=> b
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+
3
+ describe Nyan::Stage do
4
+ let(:output) { StringIO.new }
5
+ let(:stage) { Nyan::Stage.new(:output => output, :height => 5, :width => 5, :coloured => false) }
6
+ let(:sprite) { mock(:sprite) }
7
+
8
+ before do
9
+
10
+ end
11
+
12
+ describe "#initialize" do
13
+ context "when output parameter is present" do
14
+ it "sets output to the value of the output parameter" do
15
+ stage = Nyan::Stage.new(:output => output)
16
+ stage.output.should eql output
17
+ end
18
+ end
19
+
20
+ context "defaults" do
21
+ let(:default_stage) { Nyan::Stage.new }
22
+
23
+ it "sets output to $stdout" do
24
+ default_stage.output.should eql $stdout
25
+ end
26
+
27
+ it "is coloured" do
28
+ default_stage.should be_coloured
29
+ end
30
+
31
+ it "has a height equal to the terminal height" do
32
+ ::ANSI::Terminal.stub(:terminal_height => 99)
33
+ default_stage.height.should == 99
34
+ end
35
+
36
+ it "has a width equal to the terminal width" do
37
+ ::ANSI::Terminal.stub(:terminal_width => 99)
38
+ default_stage.width.should == 99
39
+ end
40
+
41
+ it "has top at 0" do
42
+ default_stage.top.should == 0
43
+ end
44
+
45
+ it "has left at 0" do
46
+ default_stage.left.should == 0
47
+ end
48
+
49
+ it "has right at width - 1" do
50
+ width = 99
51
+ default_stage.stub :width => width
52
+ default_stage.right.should == width - 1
53
+ end
54
+
55
+ it "has bottom at height - 1" do
56
+ height = 99
57
+ default_stage.stub :height => height
58
+ default_stage.bottom.should == height - 1
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "#add_sprite" do
64
+ it "adds a sprite" do
65
+ stage.add_sprite(sprite)
66
+ stage.sprites.should include(sprite)
67
+ end
68
+ end
69
+
70
+ describe "#remove_sprite" do
71
+ it "removes a sprite" do
72
+ sprite1 = double(:sprite1)
73
+ sprite2 = double(:sprite2)
74
+ stage.add_sprite(sprite1)
75
+ stage.add_sprite(sprite2)
76
+ stage.remove_sprite(sprite1)
77
+ stage.sprites.should == [sprite2]
78
+ end
79
+ end
80
+
81
+ describe "#play!" do
82
+ it "renders, animates, and cleans" do
83
+ stage.should_receive(:render)
84
+ stage.should_receive(:animate!)
85
+ stage.should_receive(:clean!)
86
+ stage.play!
87
+ end
88
+ end
89
+
90
+ describe "#render" do
91
+ let(:sprites) { double("Sprites") }
92
+ let(:sprite) { Nyan::Sprite.new }
93
+
94
+ before do
95
+ stage.stub(:sprites => sprites)
96
+ sprites.stub(:sort => [sprite])
97
+ end
98
+
99
+ it "renders its sprites to its output in order of z-index" do
100
+ sprites.should_receive(:sort).and_return([])
101
+ stage.render
102
+ end
103
+
104
+ it "prints each sprite to the output" do
105
+ sprite.frames = %w(XXXX)
106
+ stage.render
107
+ output.string.should =~ /XXXX/
108
+ end
109
+
110
+ it "only prints characters within the viewport" do
111
+ stage.stub(:height => 1, :width => 1)
112
+ sprite.x = -1
113
+ sprite.y = -1
114
+ sprite.frames = ["OOO\nOXO\nOOO"]
115
+ stage.render
116
+ output.string.should =~ /X/
117
+ output.string.should_not =~ /O/
118
+ end
119
+
120
+ it "renders each sprite at its correct position" do
121
+ sprite.x = stage.right
122
+ sprite.y = stage.bottom
123
+ sprite.frames = %w(X)
124
+ stage.render
125
+ output.string.unansi.should =~ /X$/
126
+ end
127
+
128
+ context "when coloured" do
129
+ before do
130
+ stage.stub(:coloured? => true)
131
+ end
132
+
133
+ it "prints coloured chars" do
134
+ Nyan::Colour.stub(:colourize => "__COLOURED__")
135
+ sprite.frames = %w(x)
136
+ stage.render
137
+ output.string.should =~ /__COLOURED__/
138
+ end
139
+ end
140
+ end
141
+
142
+ describe "#clean!" do
143
+ before do
144
+ stage.stub(:sprites => [sprite])
145
+ end
146
+
147
+ it "checks whether the sprite is outside the stage" do
148
+ sprite.should_receive(:outside?).with(stage)
149
+ stage.clean!
150
+ end
151
+
152
+ it "removes sprites outside the stage" do
153
+ sprite.stub(:outside? => true)
154
+ stage.clean!
155
+ stage.sprites.should_not include(sprite)
156
+ end
157
+
158
+ it "does not remove sprites inside the stage" do
159
+ sprite.stub(:outside? => false)
160
+ stage.clean!
161
+ stage.sprites.should include(sprite)
162
+ end
163
+ end
164
+
165
+ describe "#animate!" do
166
+ before do
167
+ stage.add_sprite(sprite)
168
+ end
169
+
170
+ it "updates its sprites to their next frame" do
171
+ sprite.should_receive(:animate!)
172
+ stage.animate!
173
+ end
174
+ end
175
+ end
@@ -0,0 +1 @@
1
+ require 'nyan'
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nyan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - dave@kapoq.com
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-07 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ansi
17
+ requirement: &10658100 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *10658100
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &10657680 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *10657680
37
+ - !ruby/object:Gem::Dependency
38
+ name: guard-rspec
39
+ requirement: &10657260 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *10657260
48
+ - !ruby/object:Gem::Dependency
49
+ name: rake
50
+ requirement: &10705640 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *10705640
59
+ - !ruby/object:Gem::Dependency
60
+ name: rb-inotify
61
+ requirement: &10705180 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *10705180
70
+ - !ruby/object:Gem::Dependency
71
+ name: libnotify
72
+ requirement: &10704760 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: *10704760
81
+ description: ! 'Your favourite aging meme is reheated as an RSpec custom formatter.
82
+ For entertainment purposes only. WARNING: enterprise-ready'
83
+ email:
84
+ - dave@kapoq.com
85
+ executables:
86
+ - nyan.rb
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - .rspec
92
+ - Gemfile
93
+ - Guardfile
94
+ - README.md
95
+ - Rakefile
96
+ - bin/nyan.rb
97
+ - lib/nyan.rb
98
+ - lib/nyan/colour.rb
99
+ - lib/nyan/flight.rb
100
+ - lib/nyan/formatter.rb
101
+ - lib/nyan/shape.rb
102
+ - lib/nyan/sprite.rb
103
+ - lib/nyan/sprites/cat_head.rb
104
+ - lib/nyan/sprites/pop_tart.rb
105
+ - lib/nyan/sprites/rainbow.rb
106
+ - lib/nyan/sprites/star.rb
107
+ - lib/nyan/sprites/tail.rb
108
+ - lib/nyan/stage.rb
109
+ - lib/nyan/version.rb
110
+ - nyan.gemspec
111
+ - spec/lib/colour_spec.rb
112
+ - spec/lib/shape_spec.rb
113
+ - spec/lib/sprite_spec.rb
114
+ - spec/lib/stage_spec.rb
115
+ - spec/spec_helper.rb
116
+ has_rdoc: true
117
+ homepage: https://github.com/kapoq/nyan_formatter
118
+ licenses: []
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 1.6.2
138
+ signing_key:
139
+ specification_version: 3
140
+ summary: Nyan Cat flies across your terminal while your RSpec specs run!
141
+ test_files: []