Skip to content

Instantly share code, notes, and snippets.

@pcreux
Last active July 15, 2016 23:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pcreux/445da2f6422d6f348aae to your computer and use it in GitHub Desktop.
Save pcreux/445da2f6422d6f348aae to your computer and use it in GitHub Desktop.
require 'virtus'
class User
include Virtus.model
attribute :confirmed_at, Time
attribute :subscribed, Boolean, default: false
end
class Screencast
include Virtus.model
attribute :published_at, Time
attribute :public, Boolean, default: false
def private?
!public
end
end
class Policy
def self.call(*args)
new(*args).call
end
end
class IsConfirmed < Policy
include Virtus.model
attribute :user
def call
!user.confirmed_at.nil?
end
end
class IsSubscribed < Policy
include Virtus.model
attribute :user
def call
user.subscribed?
end
end
class IsPublished < Policy
include Virtus.model
attribute :screencast
def call
!!screencast.published_at
end
end
class IsPublic < Policy
include Virtus.model
attribute :screencast
def call
screencast.public?
end
end
class IsPrivate < Policy
include Virtus.model
attribute :screencast
def call
screencast.private?
end
end
class Check
attr_reader :params
attr_reader :policies
def initialize(*args)
@params = args.pop
@policies = args
end
def ok?
failures.empty?
end
def ok!
if ok?
true
else
raise CheckFailed, "unmet conditions: #{failures.keys}"
end
end
def results
@results ||= compute_results
end
def failures
@failures ||= results.select { |_, v| v != true }
end
def compute_results
results = {}
policies.each do |policy|
results[policy] = policy.call(params)
end
results
end
CheckFailed = Class.new(StandardError)
end
def check(*args)
Check.new(*args).results
end
def check?(*args)
Check.new(*args).ok?
end
def check!(*args)
Check.new(*args).ok!
end
chuck = User.new(confirmed_at: Time.now, subscribed: true)
public_screencast = Screencast.new(published_at: Time.now, public: true)
private_screencast = Screencast.new(published_at: Time.now)
draft_screencast = Screencast.new(published_at: nil)
p check(IsConfirmed, user: chuck)
# => {IsConfirmed=>true}
p check(IsConfirmed, IsSubscribed, user: chuck)
# => {IsConfirmed=>true, IsSubscribed=>true}
p check(IsPublished, IsPublic, user: nil, screencast: public_screencast)
# => {IsPublished=>true, IsPublic=>true}
p check(IsPublished, IsPublic, user: nil, screencast: private_screencast)
# => {IsPublished=>true, IsPublic=>false}
p check(IsConfirmed, IsPublished, IsSubscribed, IsPrivate, user: chuck, screencast: private_screencast)
# => {IsConfirmed=>true, IsPublished=>true, IsSubscribed=>true, IsPrivate=>true}
p check?(IsConfirmed, IsSubscribed, IsPublished, user: chuck, screencast: draft_screencast)
# => false
p check!(IsConfirmed, IsSubscribed, IsPublished, user: chuck, screencast: draft_screencast)
# => `ok!': unmet conditions: [IsPublished] (Check::CheckFailed)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment