Created
September 21, 2009 20:54
-
-
Save royw/190546 to your computer and use it in GitHub Desktop.
This file contains 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
## | |
# Container object for a set boolean Tag objects | |
class Tagset | |
include DataMapper::Resource | |
include DataMapper::Timestamp | |
include DataMapper::Serialize | |
property :id, Serial | |
property :name, String, :index => true, :nullable => false | |
property :select_mode, Boolean, :index => true, :default => true | |
property :asserted_tags, Text, :default => '', :lazy => true | |
property :created_at, DateTime | |
property :updated_at, DateTime | |
has n, :tags, :through => Resource | |
SELECT_TAGSET_NAME = 'Select' | |
EXCLUDE_TAGSET_NAME = 'Exclude' | |
@@logger = Log4r::Logger[APP] | |
## | |
# Get the Tagset used by the filters for selecting tags | |
def self.select_tags | |
Tagset.find_or_create(:name => SELECT_TAGSET_NAME) | |
end | |
## | |
# Get the Tagset used by the filters for excluding tags | |
def self.exclude_tags | |
Tagset.find_or_create(:name => EXCLUDE_TAGSET_NAME) | |
end | |
## | |
# find or create the record specified by the given options Hash | |
# | |
# @param [Hash] options find options | |
def self.find_or_create(options) | |
obj = self.first(options) | |
if obj.nil? | |
obj = self.create(options) | |
obj.save | |
end | |
obj | |
end | |
## | |
# destroy orphaned Tagsets. Orphan is defined as any Tagset | |
# without a provider except for the two global Tagsets | |
# (select_tags and exclude_tags). | |
def self.clean | |
tagsets = Tagset.all.select{|ts| ts.provider.nil? && ts.view.nil? } - [Tagset.select_tags, Tagset.exclude_tags] | |
tagsets.each do |ts| | |
ts.destroy | |
end | |
end | |
## | |
# set the select mode | |
# | |
# @param [Boolean] mode asserted means 'OR' where deasserted means 'AND' | |
def set_select_mode(mode) | |
self.select_mode = mode | |
self.save | |
end | |
## | |
# get the selected (asserted) Tags in this Tagset | |
# | |
# @return [Array] set of asserted Tags | |
def selected | |
self.tags.reload | |
self.tags | |
end | |
## | |
# get the set of deselected (deasserted) Tags in this Tagset | |
# | |
# @return [Array] set of deasserted Tags | |
def deselected | |
Tag.all - selected() | |
end | |
## | |
# is the named Tag asserted? | |
# | |
# @param [String] name the name of a Tag object | |
# @return [Boolean] asserted if the named Tag is asserted in this Tagset | |
def asserted?(name) | |
result = false | |
tag = Tag.first(:name => name) | |
unless tag.nil? | |
result = !TagTagset.first(:tagset_id => self.id, :tag_id => tag.id).nil? | |
end | |
result | |
end | |
## | |
# set the state of the named Tag | |
# | |
# @param [String] name the name of a Tag object | |
# @param [Boolean] state the state to set the named Tag to | |
def set_tag(name, state) | |
if state | |
assert_tag(name) | |
else | |
deassert_tag(name) | |
end | |
end | |
## | |
# replace the current set of states with the given set of states | |
# note, assumes same set of tags | |
# | |
# @param [Hash] tag_states where the hash key is the Tag name and the hash value is the tag state. | |
# @return [Hash] the new set of states where the hash key is the Tag name and the hash value is the tag state. | |
def set_states(tag_states) | |
tag_states.each do |name, state| | |
set_tag(name, state) | |
end | |
states() | |
end | |
## | |
# get the current set of Tag states | |
# | |
# @return [Hash] where the hash key is the Tag name and the hash value is the tag state. | |
def states | |
states = {} | |
selected().each{|tag| states[tag.name.to_s] = true} | |
deselected().each{|tag| states[tag.name.to_s] = false} | |
states | |
end | |
## | |
# get the set of Tag names regardless of state | |
# | |
# @return [Array] an Array of String tag names | |
def names | |
tag_names = Tag.all.collect{ |tag| tag.name }.sort | |
tag_names | |
end | |
## | |
# get a String that represents the Tagset | |
# | |
# @return [String] "ALL" | "NONE" | "name1 | name2 |..." | "name1 & name2 &..." | |
def to_s | |
buf = [] | |
buf << (self.select_mode ? 'OR' : 'AND') + ' mode' | |
sel = selected() | |
if sel.empty? | |
buf << 'NONE' | |
else | |
if deselected().empty? | |
buf << 'ALL' | |
else | |
buf << sel.collect{|tag| tag.name}.sort.join(select_mode ? ' | ' : ' & ') | |
end | |
end | |
buf.join(' ') | |
end | |
def from_s(str) | |
self.select_mode = (str =~ /^\s*OR\s+mode/) | |
if str =~ /\sALL\s/ | |
assert_all_tags | |
else | |
deassert_all_tags | |
unless str =~ /\sNONE\s/ | |
names = str.split(' ') | |
if names[1] == 'mode' | |
names.shift | |
names.shift | |
end | |
names.select{|name| name !~ /^\&|\|$/}.each {|name| assert_tag(name)} | |
end | |
end | |
end | |
protected | |
def deassert_all_tags | |
deselected().each { |tag| deassert_tag(tag.name) } | |
end | |
## | |
# assert the Tag with the given Tag name | |
# | |
# @param [String] name the name of a Tag object | |
def assert_tag(name) | |
unless name =~ /^ALL|NONE$/ | |
tag = Tag.first(:name => name) | |
tag = self.tags.first(:name => name) | |
if tag.nil? | |
@@logger.debug{"asserting tag name => #{name}"} | |
tag = Tag.find_or_create(name) | |
@@logger.debug{"tag => #{tag.inspect}"} | |
@@logger.debug{"tagset => #{self.inspect}"} | |
@@logger.debug{"tags => #{self.tags.inspect}"} | |
@@logger.error{"self.tags.save failed"} unless self.tags.save | |
@@logger.error{"self.save failed"} unless self.save | |
@@logger.error{"tag.save failed"} unless tag.save | |
self.tags << tag | |
@@logger.error{"self.tags.save failed"} unless self.tags.save | |
@@logger.error{"self.save failed"} unless self.save | |
self.tags.reload | |
end | |
end | |
end | |
## | |
# deassert the Tag with the given Tag name | |
# | |
# @param [String] name the name of a Tag object | |
def deassert_tag(name) | |
tag = self.tags.first(:name => name) | |
unless tag.nil? | |
self.tag_tagsets(:tag_id => tag.id).each do |intermediate| | |
@@logger.warn{"error return from destroy"} unless intermediate.destroy | |
end | |
self.tags.reload | |
self.save | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment