public
Description: A rails tagging plugin implementing flickr's machine tags + maybe more (semantic tags)
Homepage: http://tagaholic.me/has_machine_tags/
Clone URL: git://github.com/cldwalker/has_machine_tags.git
name age message
file CHANGELOG.rdoc Thu Oct 22 19:46:19 -0700 2009 readme, rakefile, changelog [cldwalker]
file LICENSE.txt Tue Feb 10 03:07:02 -0800 2009 more tests, sticking to flickr naming conventio... [cldwalker]
file README.rdoc Thu Oct 22 19:46:19 -0700 2009 readme, rakefile, changelog [cldwalker]
file Rakefile Thu Oct 22 19:46:19 -0700 2009 readme, rakefile, changelog [cldwalker]
file VERSION.yml Thu Oct 22 19:48:56 -0700 2009 Version bump to 0.1.6 [cldwalker]
directory generators/ Wed Feb 11 13:22:53 -0800 2009 added a migration generator + better readme [cldwalker]
file has_machine_tags.gemspec Thu Oct 22 19:49:01 -0700 2009 Regenerated gemspec for version 0.1.6 [cldwalker]
file init.rb Sun Feb 22 21:43:40 -0800 2009 fixed init typo [cldwalker]
directory lib/ Fri May 01 14:00:57 -0700 2009 allow default_predicates to be a proc, updated ... [cldwalker]
directory rails/ Sat Feb 21 05:58:12 -0800 2009 adjusted init.rb to work with rake gems:install... [cldwalker]
directory test/ Thu Feb 26 15:25:58 -0800 2009 renamed singleton to finder, added finder tests [cldwalker]
README.rdoc

Description

This plugin implements Flickr’s machine tags as explained here while still maintaining standard tagging behavior.

Basically, a machine tag has a namespace, a predicate and a value in the format

    [namespace]:[predicate]=[value]

This allows for more precise tagging as tags can have unlimited contexts provided by combinations of namespaces and predicates. These unlimited contexts also make machine tags ripe for modeling relationships between objects. Read the HasMachineTags::TagMethods class documentation for a more thorough explanation.

A demo app using this plugin is here.

Install

Install as a gem

    bash> gem install has_machine_tags

    # add in your environment.rb
    config.gem "has_machine_tags"

Or as a plugin

    bash> script/plugin install git://github.com/cldwalker/has_machine_tags.git

Migrate your database from Rails root:

    bash> script/generate has_machine_tags_migration
    bash> rake db:migrate

Usage

Setup a model to use has_machine_tags

  class Url < ActiveRecord::Base
    has_machine_tags
  end

Let’s create some urls with machine tags!

    url = Url.create(:name=>"http://github.com/cldwalker/has_machine_tags",
      :tag_list=>'gem:type=tagging,flickr')

    url2 = Url.create(:name=>"http://github.com/giraffesoft/is_taggable",
      :tag_list=>'gem:type=tagging, gem:user=giraffesoft')

    url3 = Url.create(:name=>"http://github.com/datamapper/data_mapper/tree/master",
      :tag_list=>'gem:type=orm')

    url.tag_list # => ["gem:type=tagging", "flickr"]

    url.tags # => [<Tag name:"gem:type=tagging">, <Tag name:"flickr">]

Let’s query them:

    # Query urls tagged as a gem having type tagging
    Url.tagged_with 'gem:type=tagging'  # => [url, url2] from above

    # Non-machine tags work of course
    Url.tagged_with 'flickr'  # => [url] from above

    # tagged_with() is a named_scope so do your sweet chaining
    Url.tagged_with('flickr').yet_another_finder(:sweet).paginate(:per_page=>30)

Nothing interesting so far. We could’ve done the same with normal tagging.

But when we start with wildcard machine tag syntax, machine tags become more valuable:

    # Query urls tagged as gems (namespace = 'gem')
    Url.tagged_with 'gem:'  # => [url, url2, url3] from above

    # Query urls tagged as having a user, regardless of namespace and value (predicate = 'user')
    Url.tagged_with 'user='  # => [url2] from above

    # Query urls tagged as gems having a user ( namespace ='gem' AND predicate = 'user')
    Url.tagged_with 'gem:user'  # => [url2] from above

    # Query urls tagged as having a tagging value, regardless of namespace and predicate (value = 'tagging')
    Url.tagged_with '=tagging'  # => [url, url2] from above

More details on machine tag syntax can be found in the Tag class.

More Usage

The wildcard machine tag syntax can also be used to fetch tags:

    # Tags that are gems
    Tag.machine_tags 'gem:' # => [<Tag name:"gem:type=tagging">, <Tag name:"gem:user=giraffesoft">]

    # Tags that have a user predicate
    Tag.machine_tags 'user=' # => [<Tag name:"gem:user=giraffesoft">]

Of course you can do the standard tag_list manipulation:

    url.tag_list = "comma, delimited"
    url.save
    url.tag_list # =>['comma', 'delimited']

    url.tag_list = ['or', 'an', 'array']
    url.save
    url.tag_list # =>['or', 'an' 'array']

    #Add a tag
    url.tag_list << 'another_tag'
    url.save
    url.tag_list # => ["gem:type=tagging", "flickr", "another_tag']

    #Delete a tag
    url.tag_list.delete('another_tag')
    url.save
    url.tag_list # => ["gem:type=tagging", "flickr"]

Caveats

This is an experiment in progress so the api is subject to change.

Since machine tags require special characters to implement its goodness, these characters are off limit unless used in the machine tag context:

  '.', ':' , '*' , '=' , ','

Todo

  • Add a match_all option to tagged_with().
  • More helper methods ie for showing relations between namespaces, predicates + values
  • Possible add support for other ORM’s ie DataMapper.
  • Play friendly with other tagging plugins as needed.

Issues

Please report them on github.

Credits

Thanks goes to Flickr for popularizing this tagging model. Thanks also goes to the acts-as-taggable-on plugin for their finder code and the is_taggable plugin for demonstrating sane testing for a Rails plugin.