Skip to content

Instantly share code, notes, and snippets.

@wulab
Last active August 29, 2015 14:14
Show Gist options
  • Select an option

  • Save wulab/f0830fdc3d6a00125d11 to your computer and use it in GitHub Desktop.

Select an option

Save wulab/f0830fdc3d6a00125d11 to your computer and use it in GitHub Desktop.
require_relative 'model'
require 'pry'
MONTHLY_RATE = 5 # per user
class User < Model
attr_accessor :username
has_many :members
has_many :created_projects, class_name: "Project", foreign_key: :creator_id
def owned_projects
owners = Member.where(user_id: self.id, role: :owner)
Project.where(id: owners.map(&:project_id))
end
def collaborators
owned_projects.reduce(Set.new) { |s, p| s += p.users }
end
def monthly_fee
collaborators.count * MONTHLY_RATE
end
end
class Project < Model
attr_accessor :name
belongs_to :creator, class_name: "User"
has_many :members
has_many :users, through: :members
def after_save
self.add_user(self.creator, :owner)
end
def add_user(user, role)
Member.create(user_id: user.id, project_id: self.id, role: role)
end
def remove_user(user)
Member.find_by(user_id: user.id, project_id: self.id).destroy
end
end
class Member < Model
attr_accessor :role
belongs_to :user
belongs_to :project
end
if $0 == __FILE__
# user1 signs up
user1 = User.create(username: "user1")
# user1 creates Project 1
project1 = Project.create(name: "Project 1", creator_id: user1.id)
# user1 invites user2 to Project 1
user2 = User.create(username: "user2")
project1.add_user(user2, :member)
# user1 creates Project 2
project2 = Project.create(name: "Project 2", creator_id: user1.id)
# user1 invites user3 to Project 2
user3 = User.create(username: "user3")
project2.add_user(user3, :member)
# user2 creates Project 3
project3 = Project.create(name: "Project 3", creator_id: user2.id)
# user2 invites user3 to Project 3
project3.add_user(user3, :member)
# user3 creates Project 4
project4 = Project.create(name: "Project 4", creator_id: user3.id)
# Generates pricing table
puts
puts " PRICING TABLE "
puts
puts " +-------+---------------+-------------+"
puts " | user | collaborators | monthly fee |"
puts " +-------+---------------+-------------+"
User.all.each do |user|
puts " | %5s | %13d | %11s |" % [user.username, user.collaborators.count, user.monthly_fee]
end
puts " +-------+---------------+-------------+"
puts
# binding.pry
exit
end
class Model
class << self
def records
@records ||= {}
end
def objects
@objects ||= reload
end
def reload
@objects = self.clone(self.records)
end
def insert(object)
object.id = (self.records.keys.max || 0) + 1
self.records[object.id] = object.clone
reload
end
def update(object)
self.records[object.id] = object.clone
reload
end
def delete(object)
self.records.delete(object.id)
reload
end
def count
self.objects.length
end
def all
self.objects.values
end
def find(id)
if id.is_a?(Array)
self.objects.values_at(*id).compact
else
self.objects[id]
end
end
def find_by(condition)
self.where(condition).first
end
def where(condition)
self.all.select do |r|
condition.all? do |k, v|
if v.is_a?(Array)
v.include?(r.send(k))
else
r.send(k) == v
end
end
end
end
def create(attrs={})
self.new(attrs).tap(&:save)
end
def destroy(id)
self.find(id).destroy
end
##
# SuperModel Association
# http://bit.ly/15RD7GB
def belongs_to(name, options={})
class_name = options[:class_name] || self.classify(name)
foreign_key = options[:foreign_key] || "#{name}_id"
primary_key = options[:primary_key] || "id"
class_eval(<<-EOS)
attr_accessor :#{foreign_key}
def #{name}
self.#{foreign_key} && #{class_name}.find(self.#{foreign_key})
end
def #{name}=(object)
self.#{foreign_key} = object && object.#{primary_key}
end
EOS
end
def has_many(name, options={})
if through_assoc = options[:through]
class_name = self.classify(name)
foreign_key = "#{self.singularize(name)}_id"
primary_key = "id"
class_eval(<<-EOS)
def #{name}
#{foreign_key}s = self.#{through_assoc}.map(&:#{foreign_key})
#{class_name}.where(#{primary_key}: #{foreign_key}s)
end
EOS
else
class_name = options[:class_name] || self.classify(name)
foreign_key = options[:foreign_key] || "#{self.underscore(self.name)}_id"
primary_key = options[:primary_key] || "id"
class_eval(<<-EOS)
def #{name}
#{class_name}.where(#{foreign_key}: self.#{primary_key})
end
EOS
end
end
##
# ActiveSupport Inflections
# http://bit.ly/1D7yPoy
def classify(word)
self.singularize(word).gsub(/(?:^|_)(.)/) { $1.upcase }
end
def singularize(word)
result = word.to_s.dup
[
[/([^aeiouy]|qu)ies$/i, '\1y'],
[ /s$/i, '' ]
].each do |(rule, replacement)|
break if result.gsub!(rule, replacement)
end
result
end
def underscore(word)
word.to_s.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
.downcase
end
##
# SuperModel Array
# http://bit.ly/1Dgceqd
def deep_dup(array)
Marshal.load(Marshal.dump(array))
end
def clone(object)
if object.is_a?(Array) || object.is_a?(Hash)
self.deep_dup(object)
else
object.dup
end
end
end
attr_accessor :id # primary key
def initialize(attrs={})
attrs.each do |k, v|
self.send("#{k}=", v) if self.respond_to?(k)
end
end
def new_record?
self.id.nil?
end
def save
if new_record?
self.class.insert(self)
else
self.class.update(self)
end
true
end
def destroy
self.class.delete(self)
self
end
def clone
self.class.clone(self)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment