Skip to content

Instantly share code, notes, and snippets.

@FestivalBobcats
Created November 23, 2011 02:31
Show Gist options
  • Save FestivalBobcats/1387748 to your computer and use it in GitHub Desktop.
Save FestivalBobcats/1387748 to your computer and use it in GitHub Desktop.
beginning of a DSL for me to abuse embedding and linking in MongoDB
# Facets are little bits of info about visitors
# Each facet has it's own Mongo collection; however,
# Essential attributes of the facet are imbedded in an Impression.
# This greatly improves performance by avoiding extraneous lookups,
# but also links Facets to their respectful impressions, much like
# facet :has_many => :impressions
# The containing module serves to provide "facet definitions" --
# A DSL for creating the essential skeleton of a facet
module Arbiter
class << self
attr_accessor :facets
end
self.facets = []
module Facets
# Meta-magic for the syntactically lip-smacking DSL below
def self.method_missing(meth, *args, &blk)
if meth.to_s[/^[A-Z]/]# && args[0] && blk
colname = args[0]
# Instantiate a new facet class
eval "#{meth} = Class.new"
# Extend facet class
class << klass = Kernel.const_get(meth)
attr_reader :param_keys
attr_reader :parse_proc
attr_reader :key
def key(k)
@key = k
end
def parse(*k, &proc)
@param_keys = k
@parse_proc = proc
end
# Parse parameter values into Impression-mergeable hash
def parse_params(params)
vals = @param_keys.select {|k| params[k] && !params[k].empty? }
if vals.all?
{ @key => @parse_proc.call(*vals) }
end
end
end
# Apply constructor definitions to facet class
blk.call(klass)
Arbiter.facets << klass
Collection.register(colname, klass)
else
super(meth, *args, &blk)
end
end
# Facet Definitions_________________________________________
Region('regions') do
key :l
parse(:ip) do |ip|
geo = GeoIP.get_location(ip)
if geo.location
{ :_id => geo.location['_id'], :f => geo.region.f }
end
end
end
Referrer('refs') do
key :r
parse do |url|
ref = @collection.find_or_create('url' => url)
{ :_id => ref.id, :f => ref.url }
end
end
ScreenRes('screens') do
key :sr
parse(:sx, :sy) do |x, y|
@collection.find_or_create_from_dim(x, y).id
end
end
Agent('agents') do
key :a
parse do |raw|
agent = @collection.find_or_create('raw' => raw)
{ :_id => agent.id, :f => agent.raw }
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment