linked-list-0.0.14/0000755000175000017500000000000013641017110012427 5ustar fokafokalinked-list-0.0.14/LICENSE.txt0000644000175000017500000000205713641017110014256 0ustar fokafokaCopyright (c) 2013 Yury Velikanau MIT License 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. linked-list-0.0.14/linked-list.gemspec0000644000175000017500000000222213641017110016211 0ustar fokafoka# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'linked-list/version' Gem::Specification.new do |spec| spec.name = 'linked-list' spec.version = Linked::List::VERSION spec.authors = ['Yury Velikanau'] spec.email = ['yury.velikanau@gmail.com'] spec.description = %q(Ruby implementation of Doubly Linked List, following some Ruby idioms.) spec.summary = %q(Ruby implementation of Doubly Linked List, following some Ruby idioms.) spec.homepage = 'https://github.com/spectator/linked-list' spec.license = 'MIT' spec.files = `git ls-files`.split($/) spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] spec.add_development_dependency 'bundler', '>= 1.3', '<= 2.0' spec.add_development_dependency 'coveralls', '~> 0' spec.add_development_dependency 'm', '~> 1.5', '>= 1.5.0' spec.add_development_dependency 'minitest', '>= 5.0', '<= 6.0' spec.add_development_dependency 'rake', '>= 12.3.3' end linked-list-0.0.14/test/0000755000175000017500000000000013641017110013406 5ustar fokafokalinked-list-0.0.14/test/list_test.rb0000644000175000017500000004603713641017110015757 0ustar fokafokarequire 'test_helper' describe LinkedList::List do let(:list) { create_list } let(:node_1) { create_node('foo') } let(:node_2) { create_node('bar') } let(:node_3) { create_node('baz') } describe 'instantiation' do it 'assigns first to nil' do assert_nil list.first end it 'assigns last to nil' do assert_nil list.last end it 'has zero length' do assert_equal 0, list.length end end describe '#push' do it 'last pushed node can be accessed with #last' do list.push(node_1) assert_equal node_1.data, list.last end it 'last pushed node data can be accessed with #first' do list.push(node_1) assert_equal node_1.data, list.first end it 'maintains first pushed node as first' do list.push(node_1) list.push(node_2) assert_equal node_1.data, list.first end it 'sets reference to the next node' do list.push(node_1) list.push(node_2) assert_equal node_1.next, node_2 end it 'sets reference to the prev node' do list.push(node_1) list.push(node_2) assert_equal node_2.prev, node_1 end it 'increases list length by 1' do list.push(node_1) assert_equal 1, list.length end it 'returns self' do assert_equal list.push(node_1), list end end describe '#unshift' do it 'last pushed node can be accessed with #last' do list.unshift(node_1) assert_equal node_1.data, list.last end it 'last pushed node can be accessed with #first' do list.unshift(node_1) assert_equal node_1.data, list.first end it 'maintains first pushed node as last' do list.unshift(node_1) list.unshift(node_2) assert_equal node_1.data, list.last end it 'sets reference to the next node' do list.unshift(node_1) list.unshift(node_2) assert_equal node_2.next, node_1 end it 'sets reference to the prev node' do list.unshift(node_1) list.unshift(node_2) assert_equal node_1.prev, node_2 end it 'increases list length by 1' do list.unshift(node_1) assert_equal 1, list.length end it 'returns self' do assert_equal list.unshift(node_1), list end end describe '#pop' do it 'returns nil if list is empty' do assert_nil list.pop end it 'returns node from the end of the list' do list.push(node_1) list.push(node_2) assert_equal node_2.data, list.pop end it 'sets #last to nil when all nodes are removed' do list.push(node_1) list.pop assert_nil list.last end it 'sets #first to nil when all nodes are removed' do list.push(node_1) list.pop assert_nil list.first end it 'reduces list length by 1' do list.push(node_1) list.pop assert_equal 0, list.length end it 'maintains list when multiple nodes are removed' do list.push(node_1) list.push(node_2) list.pop assert_equal [node_1.data], list.to_a end end describe '#insert' do it 'raises error if after and before are passed' do err = assert_raises ArgumentError do assert_nil list.insert(1, after: 'x', before: 'y') end assert_equal err.message, 'either :after or :before keys should be passed' end it 'raises error if no after nore before are passed' do err = assert_raises ArgumentError do assert_nil list.insert(1) end assert_equal err.message, 'either :after or :before keys should be passed' end describe 'after:' do describe 'by block' do it 'does not add value if insert after not found' do list.push('foo') assert_nil list.insert(1, after: ->(d) { d == 'foo1' }) assert_equal ['foo'], list.to_a end it 'inserts value after first matching node by block' do list.push('foo') list.push('bar') assert_equal 1, list.insert(1, after: ->(d) { d == 'foo' }) assert_equal ['foo', 1, 'bar'], list.to_a assert_equal 3, list.length end describe 'position edge cases' do before do list.push(0) list.push(1) list.push(2) end it 'inserts after in the middle' do list.insert('foo', after: ->(d) { d == 0 }) assert_equal [0, 'foo', 1, 2], list.to_a end it 'inserts after the tail' do list.insert('foo', after: ->(d) { d == 2 }) assert_equal [0, 1, 2, 'foo'], list.to_a assert_equal 'foo', list.last end end end describe 'by value' do it 'does not add value if insert after not found' do list.push('foo') assert_nil list.insert(1, after: 'foo1') assert_equal ['foo'], list.to_a end it 'inserts value after first matching node by block' do list.push('foo') list.push('bar') assert_equal 1, list.insert(1, after: 'foo') assert_equal ['foo', 1, 'bar'], list.to_a assert_equal 3, list.length end describe 'position edge cases' do before do list.push(0) list.push(1) list.push(2) end it 'inserts after in the middle' do list.insert('foo', after: 0) assert_equal [0, 'foo', 1, 2], list.to_a end it 'inserts after the tail' do list.insert('foo', after: 2) assert_equal [0, 1, 2, 'foo'], list.to_a assert_equal 'foo', list.last end end end end describe ':before' do describe 'by block' do it 'does not add value if insert before not found' do list.push('foo') assert_nil list.insert(1, before: ->(d) { d == 'foo1' }) assert_equal ['foo'], list.to_a end it 'inserts value before first matching node by block' do list.push('foo') list.push('bar') assert_equal 1, list.insert(1, before: ->(d) { d == 'foo' }) assert_equal [1, 'foo', 'bar'], list.to_a assert_equal 3, list.length end describe 'position edge cases' do before do list.push(0) list.push(1) list.push(2) end it 'inserts before head' do list.insert('foo', before: ->(d) { d == 0 }) assert_equal ['foo', 0, 1, 2], list.to_a assert_equal 'foo', list.first end it 'inserts before in the middle' do list.insert('foo', before: ->(d) { d == 2 }) assert_equal [0, 1, 'foo', 2], list.to_a end end end describe 'by value' do it 'does not add value if insert before not found' do list.push('foo') assert_nil list.insert(1, before: 'foo1') assert_equal ['foo'], list.to_a end it 'inserts value before first' do list.push('foo') list.push('bar') assert_equal 1, list.insert(1, before: 'foo') assert_equal [1, 'foo', 'bar'], list.to_a assert_equal 3, list.length end describe 'position edge cases' do before do list.push(0) list.push(1) list.push(2) end it 'inserts before head' do list.insert('foo', before: 0) assert_equal ['foo', 0, 1, 2], list.to_a assert_equal 'foo', list.first end it 'inserts before in the middle' do list.insert('foo', before: 2) assert_equal [0, 1, 'foo', 2], list.to_a end end end end end describe '#insert_after_node' do it 'inserts value after passed node' do list.push('foo') list.push('bar') node = list.each_node.find { |n| n.data == 'foo' } assert_equal 1, list.insert_after_node(1, node).data assert_equal ['foo', 1, 'bar'], list.to_a assert_equal 3, list.length end describe 'position edge cases' do before do list.push(0) list.push(1) list.push(2) end it 'inserts after in the middle' do node = list.each_node.find { |n| n.data == 0 } list.insert_after_node('foo', node) assert_equal [0, 'foo', 1, 2], list.to_a end it 'inserts after the tail' do node = list.each_node.find { |n| n.data == 2 } list.insert_after_node('foo', node) assert_equal [0, 1, 2, 'foo'], list.to_a assert_equal 'foo', list.last end end end describe '#insert_after_node' do it 'inserts value before first' do list.push('foo') list.push('bar') node = list.each_node.find { |n| n.data == 'foo' } assert_equal 1, list.insert_before_node(1, node).data assert_equal [1, 'foo', 'bar'], list.to_a assert_equal 3, list.length end describe 'position edge cases' do before do list.push(0) list.push(1) list.push(2) end it 'inserts before head' do node = list.each_node.find { |n| n.data == 0 } list.insert_before_node('foo', node) assert_equal ['foo', 0, 1, 2], list.to_a assert_equal 'foo', list.first end it 'inserts before in the middle' do node = list.each_node.find { |n| n.data == 2 } list.insert_before_node('foo', node) assert_equal [0, 1, 'foo', 2], list.to_a end end end describe '#delete' do it 'raises error if block and value are passed' do err = assert_raises ArgumentError do assert_nil list.delete('x') { |d| d == 'x' } end assert_equal err.message, 'either value or block should be passed' end describe 'by block' do it 'returns nil if list is empty' do assert_nil list.delete { |d| d == 'x' } end it 'deletes value in first matching node' do calls_count = 0 list.push('foo') list.push('foo') list.push('bar') list.push('foo') list.delete { |d| calls_count += 1;d == 'bar' } assert_equal ['foo', 'foo', 'foo'], list.to_a assert_equal 3, calls_count end it 'returns deleted value' do list.push('foo') assert_equal 'foo', list.delete { |d| d == 'foo' } end it 'decreases length of list' do list.push('foo') list.push('bar') list.push('foo') list.delete { |d| d == 'foo' } assert_equal 2, list.length assert_equal ['bar', 'foo'], list.to_a end describe 'position edge cases' do before do list.push(0) list.push(1) list.push(2) end it 'deletes value from head' do list.delete { |d| d == 0 } assert_equal [1, 2], list.to_a assert_equal 1, list.first end it 'deletes value from middle' do list.delete { |d| d == 1 } assert_equal [0, 2], list.to_a end it 'deletes value from tail' do list.delete { |d| d == 2 } assert_equal [0, 1], list.to_a assert_equal 1, list.last end end end describe 'by data equality' do it 'returns nil if list is empty' do assert_nil list.delete('x') end it 'deletes value in first node' do list.push('foo') list.push('foo') list.push('bar') list.push('foo') list.delete('foo') assert_equal ['foo', 'bar', 'foo'], list.to_a end it 'returns deleted value' do list.push('foo') assert_equal 'foo', list.delete('foo') end it 'decreases length of list' do list.push('foo') list.push('bar') list.push('foo') list.delete('foo') assert_equal 2, list.length assert_equal ['bar', 'foo'], list.to_a end describe 'position edge cases' do before do list.push(0) list.push(1) list.push(2) end it 'deletes value from head' do list.delete(0) assert_equal [1, 2], list.to_a assert_equal 1, list.first end it 'deletes value from middle' do list.delete(1) assert_equal [0, 2], list.to_a end it 'deletes value from tail' do list.delete(2) assert_equal [0, 1], list.to_a assert_equal 1, list.last end end end describe 'by node' do it 'deletes first node' do list.push(node_1) list.push(node_2) list.push(node_3) list.delete(node_1) assert_equal ['bar', 'baz'], list.to_a end it 'returns deleted value' do list.push(node_1) list.delete(node_1) assert_equal node_1.data, list.delete(node_1) end it 'decreases length of list' do list.push('foo') list.push('bar') list.push('baz') list.delete('foo') assert_equal 2, list.length end describe 'position edge cases' do before do list.push(node_1) list.push(node_2) list.push(node_3) end it 'deletes value from head' do list.delete(node_1) assert_equal ['bar', 'baz'], list.to_a assert_equal 'bar', list.first end it 'deletes value from middle' do list.delete(node_2) assert_equal ['foo', 'baz'], list.to_a end it 'deletes value from tail' do list.delete(node_3) assert_equal ['foo', 'bar'], list.to_a assert_equal 'bar', list.last end end end end describe '#delete_all' do it 'raises error if block and value are passed' do err = assert_raises ArgumentError do assert_nil list.delete_all('x') { |d| d == 'x' } end assert_equal err.message, 'either value or block should be passed' end describe 'by block' do it 'returns nil if list is empty' do assert_equal list.delete_all { |d| d == 'x' }, [] end it 'deletes value in first matching node' do list.push('foo') list.push('foo') list.push('bar') list.push('foo') list.delete_all { |d| d == 'foo' } assert_equal ['bar'], list.to_a end it 'returns deleted value' do list.push('foo') assert_equal ['foo'], list.delete_all { |d| d == 'foo' } end it 'decreases length of list' do list.push('foo') list.push('bar') list.push('foo') list.delete_all { |d| d == 'foo' } assert_equal 1, list.length assert_equal ['bar'], list.to_a end end describe 'by data equality' do it 'returns nil if list is empty' do assert_nil list.delete('x') end it 'deletes all matched values' do list.push('foo') list.push('foo') list.push('bar') list.push('foo') list.delete_all('foo') assert_equal ['bar'], list.to_a end it 'returns deleted value' do list.push('foo') assert_equal ['foo'], list.delete_all('foo') end it 'decreases length of list' do list.push('foo') list.push('bar') list.push('foo') list.delete_all('foo') assert_equal 1, list.length assert_equal ['bar'], list.to_a end end end describe '#shift' do it 'returns nil if list is empty' do assert_nil list.shift end it 'returns node from the top of the list' do list.push(node_1) list.push(node_2) assert_equal node_1.data, list.shift end it 'sets #last to nil when all nodes are removed' do list.push(node_1) list.shift assert_nil list.last end it 'sets #first to nil when all nodes are removed' do list.push(node_1) list.shift assert_nil list.first end it 'reduces list length by 1' do list.push(node_1) list.shift assert_equal 0, list.length end end describe '#reverse' do it 'returns new empty list when receiver list is empty' do refute_equal list, list.reverse end it 'returns new list in reverse order' do list.push(node_1) refute_equal list.reverse, list.reverse! end it 'reverses order of nodes' do list.push(node_1) list.push(node_2) new_list = list.reverse assert_equal %w(bar foo), [new_list.first, new_list.last] end end describe '#reverse!' do it 'returns self when list is empty' do assert_equal list, list.reverse! end it 'reverses order of nodes' do list.push(node_1) list.push(node_2) list.reverse! assert_equal [node_2.data, node_1.data], [list.first, list.last] end it 'returns same object' do list.push(node_1) assert_equal list, list.reverse! end end describe '#each_node' do it 'returns enumerator if no block given' do assert_instance_of Enumerator, list.each_node end it 'pass each node data to the block' do list.push(node_1) list.push(node_2) nodes = [] list.each_node { |e| nodes << e } assert_equal %w(foo bar), nodes.map(&:data) assert_equal true, nodes.all? { |n| n.is_a?(LinkedList::Node) } end end describe '#each' do it 'returns enumerator if no block given' do assert_instance_of Enumerator, list.each end it 'pass each node data to the block' do list.push(node_1) list.push(node_2) nodes = [] list.each { |e| nodes << e } assert_equal %w(foo bar), nodes end end describe '#each_node' do it 'returns enumerator if no block given' do assert_instance_of Enumerator, list.each end it 'pass each node data to the block' do list.push(node_1) list.push(node_2) nodes = [] list.each_node { |e| nodes << e } assert_equal %w(foo bar), nodes.map(&:data) end end describe '#reverse_each' do it 'returns enumerator if no block given' do assert_instance_of Enumerator, list.each end it 'pass each node data to the block' do list.push(node_1) list.push(node_2) nodes = [] list.reverse_each { |e| nodes << e } assert_equal %w(bar foo), nodes end end describe '#reverse_each_node' do it 'returns enumerator if no block given' do assert_instance_of Enumerator, list.each end it 'pass each node data to the block' do list.push(node_1) list.push(node_2) nodes = [] list.reverse_each_node { |e| nodes << e } assert_equal %w(bar foo), nodes.map(&:data) end end describe '#inspect' do it 'includes class name' do assert_match(/LinkedList::List/, list.inspect) end it 'includes object id' do assert_match(/#{list.object_id.to_s(16)}/, list.inspect) end it 'includes node values' do list.push(node_1) assert_match(/foo/, list.inspect) end end describe 'conversion' do it '#to_list returns self' do assert_equal list, list.to_list end end end linked-list-0.0.14/test/conversions_test.rb0000644000175000017500000000147013641017110017344 0ustar fokafokarequire 'test_helper' describe LinkedList::Conversions do describe 'Node()' do it 'returns self if node is given' do node = create_node('foo') assert_equal LinkedList::Conversions.Node(node), node end it 'returns new node' do assert_instance_of LinkedList::Node, LinkedList::Conversions.Node('foo') end end describe 'List()' do it 'returns self if list is given' do list = create_list assert_equal LinkedList::Conversions.List(list), list end it 'returns list with nodes made from array' do list = LinkedList::Conversions.List([1, 2]) assert_equal [1, 2], [list.first, list.last] end it 'returns new list with one node' do list = LinkedList::Conversions.List('foo') assert_equal 'foo', list.first end end end linked-list-0.0.14/test/test_helper.rb0000644000175000017500000000045513641017110016255 0ustar fokafokaif ENV['CI'] require 'coveralls' Coveralls.wear! end require 'linked-list' gem 'minitest' require 'minitest/autorun' require 'minitest/pride' class Minitest::Spec def create_node(*args) LinkedList::Node.new(*args) end def create_list(*args) LinkedList::List.new(*args) end end linked-list-0.0.14/test/node_test.rb0000644000175000017500000000134513641017110015722 0ustar fokafokarequire 'test_helper' describe LinkedList::Node do let(:node) { create_node('foo') } describe 'instantiation' do it 'assigns data' do assert_equal 'foo', node.data end it 'assigns nil to next' do assert_nil node.next end it 'assigns nil to prev' do assert_nil node.prev end end describe 'accessors' do it '#data' do node.data = 'bar' assert_equal 'bar', node.data end it '#next' do node.next = 'bar' assert_equal 'bar', node.next end it '#prev' do node.prev = 'xyz' assert_equal 'xyz', node.prev end end describe 'conversion' do it '#to_node returns self' do assert_equal node, node.to_node end end end linked-list-0.0.14/.travis.yml0000644000175000017500000000007313641017110014540 0ustar fokafokalanguage: ruby rvm: - 2.6 cache: bundler env: CI: true linked-list-0.0.14/lib/0000755000175000017500000000000013641017110013175 5ustar fokafokalinked-list-0.0.14/lib/linked-list/0000755000175000017500000000000013641017110015414 5ustar fokafokalinked-list-0.0.14/lib/linked-list/list.rb0000644000175000017500000001676313641017110016731 0ustar fokafoka# frozen_string_literal: true module LinkedList class List include Conversions attr_reader :length alias_method :size, :length def initialize @head = nil @tail = nil @length = 0 end # Returns the first element of the list or nil. # def first @head && @head.data end # Returns the last element of the list or nil. # def last @tail && @tail.data end # Pushes new nodes to the end of the list. # # == Parameters: # node:: Any object, including +Node+ objects. # # == Returns: # +self+ of +List+ object. # def push(node) node = Node(node) @head ||= node if @tail @tail.next = node node.prev = @tail end @tail = node @length += 1 self end alias_method :<<, :push # Pushes new nodes on top of the list. # # == Parameters: # node:: Any object, including +Node+ objects. # # == Returns: # +self+ of +List+ object. # def unshift(node) node = Node(node) @tail ||= node node.next = @head @head.prev = node if @head @head = node @length += 1 self end # Inserts after or before first matched node.data from the the list by passed block or value. # # == Returns: # Inserted node data # def insert(to_add, after: nil, before: nil) if after && before || !after && !before raise ArgumentError, 'either :after or :before keys should be passed' end matcher = after || before matcher_proc = if matcher.is_a?(Proc) __to_matcher(&matcher) else __to_matcher(matcher) end node = each_node.find(&matcher_proc) return unless node new_node = after ? insert_after_node(to_add, node) : insert_before_node(to_add, node) new_node.data end # Inserts data after first matched node.data. # # == Returns: # Inserted node # def insert_after_node(data, node) Node(data).tap do |new_node| new_node.prev = node new_node.next = node.next if node.next node.next.prev = new_node else @tail = new_node end node.next = new_node @length += 1 end end # Inserts data before first matched node.data. # # == Returns: # Inserted node # def insert_before_node(data, node) Node(data).tap do |new_node| new_node.next = node new_node.prev = node.prev if node.prev node.prev.next = new_node else @head = new_node end node.prev = new_node @length += 1 end end # Removes first matched node.data from the the list by passed block or value. # # If +val+ is a +Node+, removes that node from the list. Behavior is # undefined if +val+ is a +Node+ that's not a member of this list. # # == Returns: # Deleted node's data # def delete(val = nil, &block) if val.respond_to?(:to_node) node = val.to_node __unlink_node(node) return node.data end each_node.find(&__to_matcher(val, &block)).tap do |node_to_delete| return unless node_to_delete __unlink_node(node_to_delete) end.data end # Removes all matched data.data from the the list by passed block or value. # # == Returns: # Array of deleted nodes # def delete_all(val = nil, &block) each_node.select(&__to_matcher(val, &block)).each do |node_to_delete| next unless node_to_delete __unlink_node(node_to_delete) end.map(&:data) end # Removes data from the end of the list. # # == Returns: # Data stored in the node or nil. # def pop return nil unless @head tail = __pop @head = nil unless @tail @length -= 1 tail.data end # Removes data from the beginning of the list. # # == Returns: # Data stored in the node or nil. # def shift return nil unless @head head = __shift @tail = nil unless @head @length -= 1 head.data end # Reverse list of nodes and returns new instance of the list. # # == Returns: # New +List+ in reverse order. # def reverse List(to_a).reverse! end # Reverses list of nodes in place. # # == Returns: # +self+ in reverse order. # def reverse! return self unless @head __each do |curr_node| curr_node.prev, curr_node.next = curr_node.next, curr_node.prev end @head, @tail = @tail, @head self end # Iterates over nodes from top to bottom passing node data to the block if # given. If no block given, returns +Enumerator+. # # == Returns: # +Enumerator+ or yields data to the block stored in every node on the # list. # def each return to_enum(__callee__) unless block_given? __each { |node| yield(node.data) } end # Iterates over nodes from top to bottom passing node(LinkedList::Node instance) # to the block if given. If no block given, returns +Enumerator+. # # == Returns: # +Enumerator+ or yields list nodes to the block # def each_node return to_enum(__callee__) unless block_given? __each { |node| yield(node) } end # Iterates over nodes from bottom to top passing node data to the block if # given. If no block given, returns +Enumerator+. # # == Returns: # +Enumerator+ or yields data to the block stored in every node on the # list. # def reverse_each return to_enum(__callee__) unless block_given? __reverse_each { |node| yield(node.data) } end # Iterates over nodes from bottom to top passing node(LinkedList::Node instance) # to the block if given. If no block given, returns +Enumerator+. # # == Returns: # +Enumerator+ or yields list nodes to the block # def reverse_each_node return to_enum(__callee__) unless block_given? __reverse_each { |node| yield(node) } end # Converts list to array. # def to_a each.to_a end alias_method :to_ary, :to_a def inspect sprintf('#<%s:%#x %s>', self.class, self.__id__, to_a.inspect) end # Conversion function, see +Conversions.List+. # # == Returns: # +self+ # def to_list self end private def __unlink_node(node) if node.prev.nil? node.next.prev = nil if node.next @head = node.next elsif node.next.nil? node.prev.next = nil if node.prev @tail = node.prev else node.prev.next, node.next.prev = node.next, node.prev end @length -= 1 end def __to_matcher(val = nil, &block) raise ArgumentError, 'either value or block should be passed' if val && block_given? block = ->(e) { e == val } unless block_given? ->(node) { block.call(node.data) } end def __shift head = @head @head = @head.next head.next = nil head end def __pop tail = @tail @tail = @tail.prev @tail.next = nil if @tail tail end def __reverse_each curr_node = @tail while(curr_node) yield curr_node curr_node = curr_node.prev end end def __each curr_node = @head while(curr_node) yield curr_node curr_node = curr_node.next end end end end linked-list-0.0.14/lib/linked-list/version.rb0000644000175000017500000000013413641017110017424 0ustar fokafoka# frozen_string_literal: true module Linked module List VERSION = '0.0.14' end end linked-list-0.0.14/lib/linked-list/node.rb0000644000175000017500000000050713641017110016670 0ustar fokafoka# frozen_string_literal: true module LinkedList class Node attr_accessor :data, :next, :prev def initialize(data) @data = data @next = nil @prev = nil end # Conversion function, see +Conversions.Node+. # # == Returns: # self # def to_node self end end end linked-list-0.0.14/lib/linked-list/conversions.rb0000644000175000017500000000220113641017110020304 0ustar fokafoka# frozen_string_literal: true module LinkedList module Conversions module_function # +Node()+ tries to convert its argument to +Node+ object by first calling # +#to_node+, if that is not availabe then it will instantiate a new +Node+ # object. # # == Returns: # New +Node+ object. # def Node(arg) if arg.respond_to?(:to_node) arg.to_node else Node.new(arg) end end # +List()+ tries to conver its argument to +List+ object by first calling # +#to_list+, if that is not availabe and its argument is an array (or can # be convertd into array with +#to_ary+) then it will instantiate a new # +List+ object making nodes from array elements. If none above applies, # then a new +List+ will be instantiated with one node holding argument # value. # # == Returns: # New +List+ object. # def List(arg) if arg.respond_to?(:to_list) arg.to_list elsif arg.respond_to?(:to_ary) arg.to_ary.each_with_object(List.new) { |n, l| l.push(Node(n)) } else List.new.push(Node(arg)) end end end end linked-list-0.0.14/lib/linked-list.rb0000644000175000017500000000016713641017110015745 0ustar fokafoka# frozen_string_literal: true require 'linked-list/conversions' require 'linked-list/node' require 'linked-list/list' linked-list-0.0.14/CHANGELOG.md0000644000175000017500000000302113641017110014234 0ustar fokafoka# 0.0.14 / 2020-04-17 ## Fixed Forced minimal rake version in gemspec to skip rake versions with security issues. [Compare v0.0.13...v0.0.14](https://github.com/spectator/linked-list/compare/v0.0.13...v0.0.14) # 0.0.13 / 2018-11-27 ## Fixed - Delete duplicate method definitions (nex3 in [#7](https://github.com/spectator/linked-list/pull/7)) ## Added - Allow `List#delete` to delete a `Node` in O(1) time (nex3 in [#6](https://github.com/spectator/linked-list/pull/6)) [Compare v0.0.12...v0.0.13](https://github.com/spectator/linked-list/compare/v0.0.12...v0.0.13) # 0.0.12 / 2018-09-04 ## Added - Added `insert`, `insert_before` and `insert_after` methods (mpospelov in [#3](https://github.com/spectator/linked-list/pull/3)) - Added `reverse_each` and `reverse_each_node` methods (mpospelov in [#4](https://github.com/spectator/linked-list/pull/4)) [Compare v0.0.11...v0.0.12](https://github.com/spectator/linked-list/compare/v0.0.11...v0.0.12) # 0.0.11 / 2018-08-23 ## Added - Added `delete` and `delete_all` methods (mpospelov in [#2](https://github.com/spectator/linked-list/pull/2)) [Compare v0.0.10...v0.0.11](https://github.com/spectator/linked-list/compare/v0.0.10...v0.0.11) # 0.0.10 / 2018-04-02 ## Fixed - Fixed bug when `@tail.prev` was mistekenly set to `nil` instead of `@tail.next` when popping elements off the list (Sonna in [#1](https://github.com/spectator/linked-list/pull/1)) [Compare v0.0.9...v0.0.10](https://github.com/spectator/linked-list/compare/v0.0.9...v0.0.10) # 0.0.9 / 2013-12-11 Initial release. linked-list-0.0.14/.gitignore0000644000175000017500000000023213641017110014414 0ustar fokafoka*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp linked-list-0.0.14/Rakefile0000644000175000017500000000023613641017110014075 0ustar fokafokarequire "bundler/gem_tasks" require 'rake/testtask' Rake::TestTask.new do |t| t.libs << 'test' t.pattern = 'test/*_test.rb' end task default: 'test' linked-list-0.0.14/README.md0000644000175000017500000000475413641017110013720 0ustar fokafoka[![Code Climate](https://codeclimate.com/github/spectator/linked-list.png)](https://codeclimate.com/github/spectator/linked-list) [![Build Status](https://secure.travis-ci.org/spectator/linked-list.png?branch=master)](http://travis-ci.org/spectator/linked-list) [![Gem Version](https://badge.fury.io/rb/linked-list.png)](http://badge.fury.io/rb/linked-list) [![Coverage Status](https://coveralls.io/repos/spectator/linked-list/badge.png)](https://coveralls.io/r/spectator/linked-list) # LinkedList Ruby implementation of Doubly Linked List, following some Ruby idioms. ## Installation Add this line to your application's Gemfile: ```ruby gem 'linked-list' ``` And then execute: ```shell $ bundle ``` Or install it yourself as: ```shell $ gem install linked-list ``` ## Usage ```ruby object = Object.new # could be anything list = LinkedList::List.new list.push(object) list << object # same as `push` list.unshift(object) list.pop list.shift list.insert(object, before: object) list.insert(object, before: ->(n) { n == 'foo' }) list.insert(object, after: object) list.insert(object, after: ->(n) { n == 'foo' }) list.insert_before(object, node) list.insert_after(object, node) list.reverse list.reverse! list.delete(object) list.delete { |n| n == 'foo' } list.delete_all(object) list.delete_all { |n| n == 'foo' } list.each # Enumerator object list.each { |e| puts e } list.reverse_each # Enumerator object list.reverse_each { |e| puts e } list.reverse_each_node # Enumerator object list.reverse_each_node { |node| puts node.data } list.first # head of the list list.last # tail of the list list.length list.size # same as `length` list.to_a ``` Another way to instantiate `List` or `Node` is to use conversion functions. First, include `LinkedList::Conversions` module to your class ```ruby class Foo include LinkedList::Conversions end ``` Now anywhere in your class you can use the following methods ```ruby Node(object) # will return new `Node` object List(object) # will return new `List` object with one `Node` object List([object, object]) # will return new `List` object with two `Node` objects ``` Please see `LinkedList::List`, `LinkedList::Node`, and `LinkedList::Conversions` for details. ## Tests Run test with ```shell $ rake ``` ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request linked-list-0.0.14/bin/0000755000175000017500000000000013641017110013177 5ustar fokafokalinked-list-0.0.14/bin/console0000755000175000017500000000020413641017110014563 0ustar fokafoka#!/usr/bin/env ruby # frozen_string_literal: true require 'bundler/setup' require 'linked-list' require 'irb' IRB.start(__FILE__) linked-list-0.0.14/bin/setup0000755000175000017500000000011213641017110014257 0ustar fokafoka#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install linked-list-0.0.14/Gemfile0000644000175000017500000000014013641017110013715 0ustar fokafokasource 'https://rubygems.org' # Specify your gem's dependencies in linked-list.gemspec gemspec