Permalink
Browse files

First commit

  • Loading branch information...
0 parents commit 41eb5245ccf33bb1875bd28fcd6b90c29c9a65c4 @citizen428 committed Aug 24, 2012
Showing with 271 additions and 0 deletions.
  1. +20 −0 LICENSE
  2. +95 −0 README.markdown
  3. +49 −0 Rakefile
  4. +42 −0 lib/revolver.rb
  5. BIN pkg/revolver-1.0.0.gem
  6. +11 −0 revolver.gemspec
  7. +54 −0 spec/revolver_spec.rb
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Michael Kohl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
@@ -0,0 +1,95 @@
+Description
+---
+
+A fixed size LIFO data structure, optionally free of duplicates. They feel a lot like arrays, but differ in some important arrays like indexing. This is e.g. useful for keeping a history of recent actions.
+
+Usage
+---
+
+Create a new `Revolver`:
+
+ r = Revolver.new(3)
+ #=> #<Revolver: []>
+
+Create a `Revolver` with unique elements:
+
+ r = Revolver.new(3, true)
+ #=> #<Revolver: []>
+
+Alternatively, you can create a `Revolver` from an existing array:
+
+ Revolver.from_array([*1..3], 3)
+ #=> #<Revolver: [1, 2, 3]>
+
+You can also create a unique `Revolver` that way:
+
+ Revolver.from_array([1, 1, 3], true)
+ #=> #<Revolver: [1, 3]>
+
+Add elements:
+
+ r = Revolver.new(3).push(1).push(2).push(3)
+ #=> #<Revolver: [1, 2, 3]>
+ r.push(4)
+ #=> #<Revolver: [2, 3, 4]>
+ r << 5 << 6
+ #=> #<Revolver: [4, 5, 6]>
+
+Remove an element from the end:
+
+ r.pop
+ #=> 6
+
+Check a `Revolver`'s size:
+
+ r.size
+ #=> 2
+
+A `Revolver` can be indexed like an array:
+
+ r = Revolver.from_array([*1..5])
+ #=> #<Revolver: [1, 2, 3, 4, 5]>
+ r[4]
+ #=> 5
+
+However, indices wrap around:
+
+ r[10]
+ #=> 1
+
+This also works for negative indices:
+
+ r[-1]
+ #=> 5
+ r[-6]
+ #=> 1
+ r[-8]
+ #=> 3
+
+Finally you can get a plain array out of a `Revolver`:
+
+ r.to_a
+ #=> [1, 2, 3, 4, 5]
+
+License
+---
+
+Copyright (c) 2011 Michael Kohl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
@@ -0,0 +1,49 @@
+require 'rake/testtask'
+require 'rdoc/task'
+require 'fileutils'
+GEMSPEC = 'revolver.gemspec'
+
+Rake::TestTask.new do |t|
+ t.name = :spec
+ t.test_files = FileList['spec/*_spec.rb']
+end
+
+task :default => [:spec]
+
+Rake::RDocTask.new do |rd|
+ rd.rdoc_dir = 'doc/'
+ rd.main = "README.rdoc"
+ rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
+ rd.title = 'Shenanigans'
+
+ rd.options << '--line-numbers'
+ rd.options << '--all'
+end
+
+def gemspec
+ @gemspec ||= eval(File.read(GEMSPEC), binding, GEMSPEC)
+end
+
+namespace :gem do
+ desc "Build the gem"
+ task :build => :generate_gemspec do
+ sh "gem build #{GEMSPEC}"
+ FileUtils.mkdir_p 'pkg'
+ FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", 'pkg'
+ end
+
+ desc "Install the gem locally (without docs)"
+ task :install => :build do
+ sh %{gem install pkg/#{gemspec.name}-#{gemspec.version} --no-rdoc --no-ri}
+ end
+
+ desc "Generate the gemspec"
+ task :generate_gemspec do
+ puts gemspec.to_ruby
+ end
+
+ desc "Validate the gemspec"
+ task :validate_gemspec do
+ gemspec.validate
+ end
+end
@@ -0,0 +1,42 @@
+class Revolver
+ def self.from_array(array, unique = false)
+ rev = Revolver.new(array.size, unique)
+ array.inject(rev) { |r, e| r << e }
+ end
+
+ def initialize(size, unique = false)
+ @array = []
+ @size = size
+ @unique = unique
+ end
+
+ def push(e)
+ @array.delete(e) if @unique
+ @array << e
+ @array.shift if @array.size > @size
+ self
+ end
+
+ def pop
+ @array.pop
+ end
+
+ def [](i)
+ @array[i % @size]
+ end
+
+ def size
+ @array.size
+ end
+
+ def to_a
+ @array
+ end
+
+ def to_s
+ "#<Revolver: #{@array.inspect}>"
+ end
+
+ alias :<< :push
+ alias :to_ary :to_a
+end
Binary file not shown.
@@ -0,0 +1,11 @@
+Gem::Specification.new do |gem|
+ gem.name = 'revolver'
+ gem.version = '1.0.0'
+ gem.author = 'Michael Kohl'
+ gem.email = 'citizen428@gmail.com'
+ gem.summary = 'A fixed-size LIFO data structure'
+ gem.homepage = 'http://citizen428.github.com/revolver/'
+ gem.require_paths = %w[lib]
+ gem.files = %w[lib/revolver.rb ./LICENSE ./README.markdown]
+ gem.has_rdoc = false
+end
@@ -0,0 +1,54 @@
+require 'minitest/spec'
+require 'minitest/autorun'
+require 'revolver'
+
+describe Revolver do
+ before do
+ @empty = Revolver.new(3)
+ @full = Revolver.new(3).push(1).push(2).push(3)
+ end
+
+ it "creates a new Revolver from an array" do
+ r = Revolver.from_array([*1..5])
+ r.must_be_kind_of(Revolver)
+ r.to_a.must_equal([1, 2, 3, 4, 5])
+ end
+
+ it "returns an array representation of itself" do
+ @empty.to_a.must_be_empty
+ @full.to_a.must_equal([1, 2, 3])
+ end
+
+ it "tells you how many elements it contains" do
+ @empty.size.must_equal(0)
+ end
+
+ it "does not grow over the specified size" do
+ @full.push(4).size.must_equal(3)
+ end
+
+ it "chains calls to #push/#<<" do
+ (@full << 4 << 5).to_a.must_equal([3, 4, 5])
+ end
+
+ it "pops an element off the end" do
+ (@full).pop.must_equal(3)
+ @full.to_a.must_equal([1, 2])
+ end
+
+ it "can be indexed like an array" do
+ @full[1].must_equal(2)
+ @full[-1].must_equal(3)
+ end
+
+ it "wraps around when indexing is out of bounds" do
+ @full[5].must_equal(3)
+ @full[-4].must_equal(3)
+ end
+
+ it "doesn't allow duplicates when created with the 'unique' option" do
+ r = Revolver.new(3, true).push(1).push(1).push(2)
+ r.push(1).to_a.must_equal([2, 1])
+ end
+
+end

0 comments on commit 41eb524

Please sign in to comment.