Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
shenoudab committed May 31, 2010
0 parents commit 1023636
Show file tree
Hide file tree
Showing 21 changed files with 600 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pkg/*
nbproject/*.gitignore
20 changes: 20 additions & 0 deletions MIT-LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2010 mobiThought

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 changes: 27 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
WurflStore : Wurfl Redis Store
============

Wurfl Redis Store

Installation
============

Install the gem from gemcutter:

sudo gem install wurfl_store

Special Thanks
==============

WurflStore was inspired and based on wurfl_store . Many thanks to the authors and contributors.


Feedback
========

Send Feedback and questions to: sbertel at mobithought.com


More will Coming Soon, Wait for MobiThought

Copyright (c) 2010 Shenouda Bertel, MobiThought, released under the MIT license
51 changes: 51 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
require 'rubygems'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/gempackagetask'

desc 'Default: run unit tests.'
task :default => :test

desc 'Test the wurfl_store plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end

desc 'Generate documentation for the wurfl_store gem.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'WurflStore'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end

PKG_FILES = FileList[ '[a-zA-Z]*', 'generators/**/*', 'lib/**/*', 'test/**/*' ]

spec = Gem::Specification.new do |s|
s.name = "wurfl_store"
s.version = "0.1.0"
s.authors = ["Shenouda Bertel"]
s.description = "Wurfl Redis Store"
s.email = "[email protected]"
s.homepage = "http://mobithought.com/"
s.files = PKG_FILES.to_a
s.require_paths = ["lib"]
s.rubyforge_project = "wurfl_store"
s.rubygems_version = "1.3.6"
s.summary = "Wurfl Redis Store"
s.platform = Gem::Platform::RUBY
s.add_dependency('redis-store')
s.add_dependency('nokogiri')
s.has_rdoc = false
s.extra_rdoc_files = ["README"]
end

desc 'Turn this plugin into a gem.'
Rake::GemPackageTask.new(spec) do |pkg|
pkg.gem_spec = spec
end
4 changes: 4 additions & 0 deletions init.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require 'wurfl_store'
ActionController::Base.send(:include, WurflStore::Filter)
ActionView::Base.send(:include, WurflStore::View)
WurflStore.init
6 changes: 6 additions & 0 deletions install.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Create necessary directory for wurfl.xml/pstore if it doesn't already exist.
puts 'Creating wurfl directory at' + Rails.root.join('tmp', 'wurfl')
FileUtils.mkdir_p(Rails.root.join('tmp', 'wurfl'))

FileUtils.cd(Rails.root)
'rake wurfl:update'
23 changes: 23 additions & 0 deletions lib/tasks/wurfl_store_tasks.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace :wurfl do
desc "Download the latest wurfl.xml.gz and unpack it."
task :update do
require Pathname.new(File.dirname(__FILE__)).join('..', 'wurfl_store', 'wurfl', 'wurfl_load')

FileUtils.mkdir_p(Rails.root.join('tmp', 'wurfl'))
FileUtils.cd(Rails.root.join('tmp', 'wurfl'))

return_code = `wget -N -- http://downloads.sourceforge.net/project/wurfl/WURFL/latest/wurfl-latest.xml.gz`.to_i
raise 'Failed to download wurfl-latest.xml.gz' unless return_code == 0

return_code = `gunzip -c wurfl-latest.xml.gz > wurfl.xml`.to_i
raise 'Failed to unzip wurfl-latest.xml.gz' unless return_code == 0
end

desc "Load the latest XML file into the cache."
task :cache_update do
require Pathname.new(File.dirname(__FILE__)).join('..', 'wurfl_store', 'cache_initializer')
require Rails.root.join('config', 'environment.rb')
puts 'This can take a minute or two. Be patient.'
WurflStore::CacheInitializer.refresh_cache
end
end
30 changes: 30 additions & 0 deletions lib/wurfl_store.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
require 'wurfl_store/cache_initializer'
require 'wurfl_store/view'
require 'wurfl_store/filter'
require 'rubygems'
require 'activesupport'
require 'redis-store'

module WurflStore
attr_accessor :cache
def self.cache
@cache
end

def self.init
@cache = ActiveSupport::Cache.lookup_store(:redis_store)
# determine if the cache has been initialized with the wurfl
CacheInitializer.initialize_cache if WurflStore.cache.read('wurfl_initialized').nil?
end

def self.get_handset(user_agent)
return nil if user_agent.nil?
CacheInitializer.cache_initialized?
user_agent.slice!(250..-1)
handset = @cache.read(user_agent.tr(' ', ''))
chopped_user_agent = user_agent.chop
return nil if chopped_user_agent.empty?
return self.get_handset(chopped_user_agent) if handset.nil?
return handset
end
end
47 changes: 47 additions & 0 deletions lib/wurfl_store/cache_initializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require Pathname.new(File.dirname(__FILE__)).join('wurfl', 'wurfl_load')

module WurflStore
module CacheInitializer
def self.load_wurfl
wurfl_loader = WurflLoader.new
path_to_wurfl = Rails.root.join('tmp', 'wurfl', 'wurfl.xml')
unless path_to_wurfl.exist?
puts 'Could not find wurfl.xml. Have you run rake wurfl:update yet?'
Process.exit
end
return wurfl_loader.load_wurfl(path_to_wurfl)
end

def self.cache_initialized?
return true if WurflStore.cache.read('wurfl_initialized')
initialize_cache
loop do
break if WurflStore.cache.read('wurfl_initialized')
sleep(0.1)
end
return true
end

def self.initialize_cache
# Prevent more than one process from trying to initialize the cache.
return unless WurflStore.cache.write('wurfl_initializing', true, :unless_exist => true)

WurflStore.cache.write('wurfl_initialized', false)
# Proceed to initialize the cache.
xml_to_cache
WurflStore.cache.write('wurfl_initializing', false)
end

def self.xml_to_cache
handsets, fallbacks = load_wurfl
handsets.each_value do |handset|
WurflStore.cache.write(handset.user_agent.tr(' ', ''), handset)
end
WurflStore.cache.write('wurfl_initialized', true)
end

def self.refresh_cache
xml_to_cache
end
end
end
12 changes: 12 additions & 0 deletions lib/wurfl_store/filter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module WurflStore
module Filter

def set_wurfl
return unless session[:handset_checked].nil?
handset = WurflStore.get_handset(request.headers['HTTP_USER_AGENT'])
session[:handset_agent] = handset.user_agent unless handset.nil?
session[:handset_checked] = true
end

end
end
24 changes: 24 additions & 0 deletions lib/wurfl_store/view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module WurflStore
module View

def handset
WurflStore.get_handset(session[:handset_agent])
end

def handset_capability(capability)
return nil if handset.nil?
capability = handset[capability]
return nil if capability.nil?
case capability.strip
when /^d+$/
capability = capability.to_i
when /^true$/i
capability = true
when /^false$/i
capability = false
end
return capability
end

end
end
121 changes: 121 additions & 0 deletions lib/wurfl_store/wurfl/wurfl_load.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
require Pathname.new(File.dirname(__FILE__)).join('wurflhandset')
require 'rubygems'
require 'nokogiri'

# Modified to use nokogiri. GREATLY increased speed.
# $Id: wurflloader.rb,v 1.1 2003/11/23 12:26:05 zevblut Exp $
# Authors: Zev Blut ([email protected])
# Copyright (c) 2003, Ubiquitous Business Technology (http://ubit.com)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# * Neither the name of the WURFL nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

class WurflLoader
def initialize
@handsets = Hash::new
@fallbacks = Hash::new
end

def load_wurfl(wurflfile)
file = File.new(wurflfile)
doc = Nokogiri::XML::Document.parse file

# read counter
rcount = 0

# iterate over all of the devices in the file
doc.xpath("wurfl/devices/device").each do |element|

rcount += 1
hands = nil # the reference to the current handset
if element.attributes["id"].to_s == "generic"
# setup the generic Handset
element.attributes["user_agent"] = "generic"
if @handsets.key?("generic") then
hands = @handsets["generic"]
puts "Updating the generic handset at count #{rcount}" if @verbose
else
# the generic handset has not been created. Make it
hands = WurflHandset::new "generic","generic"
@handsets["generic"] = hands
@fallbacks["generic"] = Array::new
puts "Made the generic handset at count #{rcount}" if @verbose
end

else
# Setup an actual handset

# check if handset already exists.
wurflid = element.attributes["id"].to_s
if @handsets.key?(wurflid)
# Must have been created by someone who named it as a fallback earlier.
hands = @handsets[wurflid]
else
hands = WurflHandset::new "",""
end
hands.wurfl_id = wurflid
hands.user_agent = element.attributes["user_agent"].to_s
hands.user_agent = 'generic' if hands.user_agent.empty?

# get the fallback and copy it's values into this handset's hashtable
fallb = element.attributes["fall_back"].to_s

# for tracking of who has fallbacks
if !@fallbacks.key?(fallb)
@fallbacks[fallb] = Array::new
end
@fallbacks[fallb]<< hands.user_agent

# Now set the handset to the proper fallback reference
if !@handsets.key?(fallb)
# We have a fallback that does not exist yet, create the reference.
@handsets[fallb] = WurflHandset::new "",""
end
hands.fallback = @handsets[fallb]
end

# now copy this handset's specific capabilities into it's hashtable
element.xpath("./*/capability").each do |el2|
hands[el2.attributes["name"].to_s] = el2.attributes["value"].to_s
end
@handsets[hands.wurfl_id] = hands

# Do some error checking
if hands.wurfl_id.nil?
puts "a handset with a nil id at #{rcount}"
elsif hands.user_agent.nil?
puts "a handset with a nil agent at #{rcount}"
end
end
return @handsets, @fallbacks
end

end
Loading

0 comments on commit 1023636

Please sign in to comment.