
Security News
Nx npm Packages Compromised in Supply Chain Attack Weaponizing AI CLI Tools
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socket’s AI scanner detected the supply chain attack and flagged the malware.
A collection of data structures in Ruby, made for my data structures challenge
gem install datastructures
A queue is a simple container-based structure that mimics a real-life queue (e.g. waiting in line at the bank). It is FIFO (first-in-first-out), meaning that when you retrieve items from the queue, they are returned in the order in which they entered. Ruby Arrays provide methods that make Queue implementation trivially easy, but having them named appropriately and contained in a convenience class is worth it to see how they are implemented, and because other structures will inherit from this one. An alternate implementation could be done using a linked list.
Usage:
require 'datastructures'
queue = DataStructures::Queue.new
queue.enqueue('first')
queue.enqueue('second')
queue.size # => 2
queue.empty? # => false
queue.front # => 'first'
queue.back # => 'second'
queue.dequeue # => 'first'
queue.dequeue # => 'second'
queue.dequeue # => RuntimeError, "Queue underflow: nothing to dequeue"
The stack is the sibling of the queue. It mimicks a real-life stack (e.g. of paper). It is FILO (first-in-last-out), so that when items are retrieved from the stack, they are returned in the reverse of the order in which they were added. Again, Ruby Arrays provide a perfect container. As with the Queue, it could also be implemented using a linked list.
Usage:
require 'datastructures'
stack = DataStructures::Stack.new
stack.push('first')
stack.push('second')
stack.size # => 2
stack.empty? # => false
stack.top # => 'second'
stack.bottom # => 'first'
stack.pop # => 'second'
stack.pop # => 'first'
stack.pop # => RuntimeError, "Stack underflow: nothing to pop"
A tree is a directed graph where any two nodes are connected by only one edge, and there is a specified 'root' node, away from which all edges are directed. For any edge, the node that it points from is the parent, and the node it points to is the child. This implementation is currently very crude, and I hope to expand it by:
Currently the implementation offers the ability to construct a tree and traverse it manually using family methods (parent, child, siblings, descendents). Nodes can have associated data.
require 'datastructures'
# start with a root TreeNode
tree = DataStructures::TreeNode.new('root node')
tree.is_root? # => true
tree.is_leaf? # => true
# children are also TreeNodes
child1 = DataStructures::TreeNode.new('child')
tree.add_child(child1)
tree.child_count # => 1
tree.add_child(DataStructures::TreeNode.new('another child'))
tree.child_count # => 2
tree.is_root? # => true
tree.is_leaf? # => false
child1.is_leaf? # => true
# we can traverse by querying the family
tree.siblings # => []
child1.siblings.map{ |sibling| sibling.data } # => ["another child"]
child1.parent == tree # => true
child1.parent == child.siblings.first.parent # => true
tree.descendents.map { |d| d.data } # => ["child", "another child"]
A linked list is a group of items which are ordered, and where the ordering is determined solely by the information each item contains about its neighbours.
This implementation is a doubly-linked list, which means that each item retains a reference to the next and previous items in the list.
The advantage of a linked list over a traditional array is that elements can be inserted and deleted efficiently.
ll = DataStructures::LinkedList.new('one')
ll.first.data # => 'one'
ll[0] # => 'one'
ll << 'two' # => ["one", "two"]
ll.size # => 2
ll.length # => 2
ll.last.data # => 'two'
ll[ll.size - 1] # => 'two'
# linked lists can act as stacks
ll.push 'three' # => ["one", "two", "three"]
ll.size # => 3
ll.pop # => "three"
ll.size # => 2
puts ll # => ["one", "two"]
# or as queues
ll.push 'three' # => ["one", "two", "three"]
ll.shift # => 'one'
ll.size # => 2
ll.first.data 'two'
# we can insert and delete
ll.insert(1, 'one point five') # => ["two", "one point five", "three"]
ll.delete(1)
ll.to_s # => ['two', 'three']
An adjacency list is a structure for representing a graph. Nodes are named; the name can be any hashable object. Data can be stored in nodes, but not edges. The graph can be traversed manually by querying the neighbours of a node.
The implementation is currently basic. I plan to improve it by:
require 'datastructures'
al = DataStructures::AdjacencyList.new
al.add('one', 1, [2])
al.add('two', 2, [3])
al.add('three', 3, [1])
al.add('four', 4, [2])
al.get_node_value(1) # => 'one'
al.set_node_value(1, 'new value')
al.neighbours(1) # => [2]
al.adjacent?(2, 3) # => true
al.adjacent?(1, 4) # => false
al.add_edge(1, 4)
al.adjacent?(1, 4) # => true
al.delete_edge(2, 3)
al.adjacent?(2, 3) # => false
al.to_s
# 1 (new value) => [2, 4]
# 2 (two) => []
# 3 (three) => [1]
# 4 (four) => [2]
FAQs
Unknown package
We found that datastructures demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socket’s AI scanner detected the supply chain attack and flagged the malware.
Security News
CISA’s 2025 draft SBOM guidance adds new fields like hashes, licenses, and tool metadata to make software inventories more actionable.
Security News
A clarification on our recent research investigating 60 malicious Ruby gems.