Created
July 27, 2011 11:26
-
-
Save joshnesbitt/1109177 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| # 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 ] |
This file contains hidden or 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 '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 |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Known issues: