Skip to content

Instantly share code, notes, and snippets.

@mauricioszabo
Last active April 28, 2018 02:48
Show Gist options
  • Save mauricioszabo/a8f21571b341a0d8659491e0daceb2e6 to your computer and use it in GitHub Desktop.
Save mauricioszabo/a8f21571b341a0d8659491e0daceb2e6 to your computer and use it in GitHub Desktop.
Anima's Examples
require "hamster"
require "benchmark"
require "set"
TIMES = 2_000_000
Benchmark.bmbm do |r|
x = arr = nil
r.report("Mutable array - push") do
x = []
TIMES.times do |i|
x << i
x << rand
end
arr = x.dup
end
r.report("Mutable array - pop") do
(TIMES * 2).times do |i|
x.pop()
end
end
r.report("Mutable array - unshift") do
x = []
TIMES.times do |i|
x.unshift i
x.unshift rand
end
end
r.report("Mutable array - get random element") do
TIMES.times do
x[rand(TIMES)]
end
end
r.report("Mutable array - shift") do
(TIMES * 2).times do |i|
x.shift()
end
end
r.report("Immutable list - prepend") do
x = Hamster::List[]
TIMES.times do |i|
x = x.add(i).add(rand)
end
end
r.report("Immutable list - shift") do
(TIMES * 2).times do |i|
x = x.tail
end
end
r.report("Immutable deque - append at last") do
x = Hamster::Deque[]
TIMES.times do |i|
x = x.push(i)
x = x.push(rand)
end
end
r.report("Immutable deque - pop") do
(TIMES * 2).times do |i|
x = x.pop()
end
end
r.report("Immutable deque - append at first") do
x = Hamster::Deque[]
TIMES.times do |i|
x = x.unshift(i)
x = x.unshift(rand)
end
end
r.report("Immutable deque - shift") do
(TIMES * 2).times do |i|
x = x.shift()
end
end
r.report("Immutable vector") do
x = Hamster::Vector[]
TIMES.times do |i|
x = x << i
x = x << rand
end
end
r.report("Mutable vector - get random element") do
TIMES.times do
x[rand(TIMES)]
end
end
r.report("Mutable vector - pop") do
y = x
(TIMES * 2).times do
x.pop
end
end
r.report("Mutable SET") do
x = Set[]
TIMES.times do |i|
x << i
x << rand
end
end
r.report("Mutable SET - check element") do
TIMES.times do |i|
x.include?(i + 2)
end
end
r.report("Immutable SET") do
x = Hamster::Set[]
TIMES.times do |i|
x = x.add?(i)
x = x.add?(rand)
end
end
r.report("Immutable SET - check element") do
TIMES.times do |i|
x.include?(i + 2)
end
end
r.report("Immutable list - from mutable") do
Hamster::List[*arr]
end
r.report("Immutable Deque - from mutable") do
Hamster::Deque[*arr]
end
r.report("Immutable Vector - from mutable") do
Hamster::Vector[*arr]
end
r.report("Immutable Set - from mutable") do
Hamster::Set[*arr]
end
end;nil
require 'sequel'
require "sqlite3"
require "json"
require "anima"
require "hamster"
require "dry-validation"
DB = Sequel.connect('sqlite:/')
Sequel.extension :migration
Sequel::Model.plugin :timestamps
class CreateAll < Sequel::Migration
def up
create_table(:users) do
primary_key :id
String :name, null: false
String :email, null: true
end
create_table(:tasks) do
primary_key :id
foreign_key :user_id, :users
column :title, String, null: false
end
end
end
CreateAll.apply(DB, :up)
DB[:users].insert(name: "Foo Bar")
NameValidation = Dry::Validation.Schema do
required(:name).filled
end
# This is NOT a good implementation of `Either` monad:
# ideally, it would need to check if return code is an
# Either class, then "flatten" the structure
# the same as JS Promise do
class Either
def self.left(val)
new(val, nil, false)
end
def self.right(val)
new(nil, val, true)
end
def initialize(left, right, is_right)
@left, @right = left, right
@is_right = is_right
end
private :initialize
def get!
raise ArgumentError.new("Left value") unless @is_right
@right
end
def error
@left
end
def then
if @is_right
Either.right(yield @right)
else
self
end
end
def or_else
if @is_right
self
else
Either.left(yield @left)
end
end
end
class User
extend Sequel::Model::ClassMethods
include Anima.new(:id, :name, :email)
self.dataset = DB[:users]
def self.call(param)
new(param)
end
def update!(params)
validate(params).then do |new_obj|
pk = self.class.primary_key
pk_value = send(pk)
self.class.dataset.where(pk => pk_value).update(new_obj.to_h)
new_obj
end
end
private :with
private def validate(params)
new_obj = with(params)
errors = NameValidation.call(new_obj.to_h).errors
if(errors.empty?)
Either.right(new_obj)
else
Either.left(errors)
end
end
end
u = User.first
u2 = u.update!(name: "")
u2 = u.update!(email: "[email protected]")
u2 = u.update!(name: "Szabo")
require "anima"
require "hamster"
module UpInAnima
def update_in(arg, *rest, &b)
value = self.send(arg)
if(rest.size == 0)
with(arg => b.call(value))
else
with(arg => value.update_in(*rest, &b))
end
end
end
class User
include Anima.new(:name, :children)
include UpInAnima
NULL = new(name: "", children: Hamster::Vector[])
end
class Children
include Anima.new(:name, :age)
include UpInAnima
NULL = new(name: "", age: 0)
end
user = User::NULL.with(
name: "Ariovaldo",
children: Hamster::Vector[
Children::NULL.with(name: "Emily", age: 9)
]
)
# Emily's birthday!
user.update_in(:children, 0, :age) { |x| x + 1 }
require "sinatra"
require_relative "database_access"
class User
def self.call(param)
User::Valid.new(param)
end
private def validate(params)
new_obj = with(params)
obj_hash = new_obj.to_h
errors = NameValidation.call(obj_hash).errors
if(errors.empty?)
Either.right(new_obj)
else
Either.left(User::Invalid.new(obj_hash, errors))
end
end
end
class User::Valid < User
end
class User::Invalid < User
attr_reader :errors
def initialize(params, errors)
super(params)
@errors = errors.freeze
end
end
get "/" do
@users = User.all
erb :index
end
get "/:id/edit" do |id|
@user = User[id]
erb :edit
end
post "/:id" do |id|
@user = User[id]
user_params = params[:user].map { |k, v| [k.to_sym, v] }.to_h
@user.update!(user_params).then { |new_user|
return redirect "/#{new_user.id}/edit"
}.or_else { |user|
@user = user
return erb :edit
}
end
__END__
@@ index
<h1>Users</h1>
<ul>
<% @users.each do |user| %>
<li>
<%= user.name %> -> <%= user.email || "no e-mail configured" %>
<a href="/<%= user.id %>/edit">Edit</a>
</li>
<% end %>
</ul>
@@ edit
<h1>Editing <%= @user.name %></h1>
<% if @user.is_a?(User::Invalid) %>
<h2>Errors validating...</h2>
<ul>
<% @user.errors.each do |field, values| %>
<li><%= field %>: <%= values.join(", ") %></li>
<% end %>
</ul>
<% end %>
<form action="/<%= @user.id %>" method="POST">
<p>Name: <input type="text" value="<%= @user.name %>" name="user[name]"></p>
<p>E-Mail: <input type="text" value="<%= @user.email %>" name="user[email]"></p>
<p><input type="submit" value="Save"></p>
</form>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment