Skip to content

Instantly share code, notes, and snippets.

@RolandStuder
Last active January 14, 2022 00:27
Show Gist options
  • Save RolandStuder/56e212b24c94fbf831ef922ce14a625b to your computer and use it in GitHub Desktop.
Save RolandStuder/56e212b24c94fbf831ef922ce14a625b to your computer and use it in GitHub Desktop.
require "minitest/autorun"
class AllFutures
class Relation
attr_accessor :records
def initialize(records= [], klass: nil)
@records = records
@klass = klass
end
def to_a
records.to_a
end
# example of a custom method
def where(included_thing)
self.records = records.select{ |record| record.to_s.include? included_thing.to_s }
self
end
# respond to enumerable methods
def respond_to_missing?(method_name, include_private = true)
Enumerable.instance_methods.include?(method_name) ||
records[0].class.methods.include?(method_name)
end
# on enumerable methods check if they return an array, if yes wrap it again as a relation
def method_missing name, *args, &block
# handle enumerable methods
if @records.respond_to? name
res = @records.send name, *args, &block
if res.kind_of?( Array )
AllFutures::Relation.new(res)
else
res
end
# handle class methods of records
elsif @records.first.class.methods.include?(name)
# reset what is in the records class
temp_class = @klass.dup
temp_class.set_records(@records.map(&:value))
@records = temp_class.send(name, *args, &block)
else
super
end
end
end
def handle_missing_enumerable_methods(name, *args, &block)
res = @records.send name, *args, &block
if res.kind_of?( Array )
AllFutures::Relation.new(res, klass: @klass)
else
res
end
end
end
class AllFutures::Record
@records = []
def self.set_records(values)
@records = values.map { |value| new(value)}
end
def self.all
AllFutures::Relation.new(@records, klass: self)
end
def self.where(included_thing)
all.where(included_thing)
end
end
class Thing < AllFutures::Record
attr_accessor :value
def self.z_only
where("z")
end
def initialize(value)
self.value = value
end
def to_s
value.to_s
end
end
class AllFutures::RelationTest < Minitest::Test
def setup
@list = AllFutures::Relation.new
end
def test_can_initialize
assert AllFutures::Relation.new
end
def test_converts_to_array
assert_kind_of Array, @list.to_a
end
def test_can_add_array
other_array = (1..10).to_a
@list += other_array
assert_includes @list, 1
end
def test_can_add_single_item
thing = "Hello"
@list << thing
assert_includes @list, thing
assert_kind_of AllFutures::Relation, @list
end
def test_can_select
@list = AllFutures::Relation.new((1..20).to_a)
assert_kind_of AllFutures::Relation, @list
assert_kind_of AllFutures::Relation, @list.select { true }
end
def test_can_map
@list = AllFutures::Relation.new((1..20).to_a)
assert_kind_of AllFutures::Relation, @list.map { rand(10) }
end
def test_can_use_cutoms_where
@list = AllFutures::Relation.new(("a".."z").to_a.permutation(2))
reduced_list = @list.first(10).where("a").first(3)
assert_kind_of AllFutures::Relation, reduced_list
end
def test_relations_responds_to_class_method_of_object
@list = AllFutures::Relation.new([Thing.new("Hello")])
assert @list.respond_to? :z_only
end
def test_can_set_collection
records = Thing.set_records([1,1,1,1,1,2,3])
assert Thing.all
assert_equal 1, Thing.where(1).first.value
end
def test_applies_class_method_to_list
records = Thing.set_records(["z","z","z", "x"])
assert Thing.z_only.all? { _1.value == "z"}
end
def test_can_select_then_apply_custom_method
records = Thing.set_records(["z", "x"])
assert Thing.where("z")
assert_kind_of AllFutures::Relation, Thing.where("z")
assert_kind_of AllFutures::Relation, Thing.z_only
assert_kind_of AllFutures::Relation, Thing.all.z_only
assert Thing.all.z_only.all.all? { _1.value == "z"}
assert_equal 2, Thing.all.size
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment