Last active
January 14, 2022 00:27
-
-
Save RolandStuder/56e212b24c94fbf831ef922ce14a625b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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