Skip to content

Instantly share code, notes, and snippets.

@joshnesbitt
Created July 27, 2011 11:26
Show Gist options
  • Select an option

  • Save joshnesbitt/1109177 to your computer and use it in GitHub Desktop.

Select an option

Save joshnesbitt/1109177 to your computer and use it in GitHub Desktop.
# Random idea to use a single integer attribute to store information
# about a group of predefined items on any given object. More about
# bitwise operations and bit shifting: http://en.wikipedia.org/wiki/Bitwise_operation
require 'groupable'
class User
include Groupable
group :roles, %w{ basic admin }
end
user = User.new
# API
# Adding item:
user.roles.add(:basic)
# Removing item:
user.roles.remove(:basic)
# Checking item presence within group:
user.roles.has?(:basic) # => false
# Checking all items within group are present:
user.roles.has_all? # => false
# Inspecting:
user.roles.keys # => [ :basic ]
user.roles.to_a # => [ :basic ]
user.roles.inspect # => [ :basic ]
require 'rubygems'
require 'active_support/core_ext'
module Groupable
class GroupProxy
def initialize(group)
@group = group
@state = 0
end
def add(key)
@state |= @group.lookup[key]
end
def remove(key)
# TODO
end
def has?(key)
@state & @group.lookup[key] == @group.lookup[key]
end
def has_all?
@state == @group.lookup.values.inject(0) { |t, v| t + v }
end
def keys
@group.lookup.reject { |k, v| !has?(k) }.keys
end
alias_method :to_a, :keys
def inspect
to_a.inspect
end
end
class Group
attr_reader :name, :lookup
def initialize(name, items = [])
@name = name
@lookup = {}
items.each do |key|
define_item(key)
end
end
def define_proxy(obj)
method = name
proxy = GroupProxy.new(self)
obj.class_eval do
define_method(method) { proxy }
end
end
private
def define_item(key)
@lookup[key.to_sym] = (1 << next_index)
end
def next_index
@lookup.empty? ? 0 : (@lookup.values.sort.last + 1)
end
end
end
module Groupable
extend ActiveSupport::Concern
included do
class_attribute :groups
end
module ClassMethods
def group(key, items)
group = Group.new(key, items)
group.define_proxy(self)
self.groups ||= {}
self.groups[key.to_sym] = group
end
end
end
@joshnesbitt
Copy link
Copy Markdown
Author

Known issues:

  • If an item is added/removed it will disrupt the bit value of any preceding items.
  • Can't currently remove items (needs implementing)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment