Permalink
Browse files

Initial import

  • Loading branch information...
0 parents commit 1023636ed3e3c0ada96e3b845b1c456cf9f4e5f1 @shenoudab committed May 31, 2010
@@ -0,0 +1,2 @@
+pkg/*
+nbproject/*.gitignore
@@ -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.
@@ -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
@@ -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 = "sbertel@mobithought.com"
+ 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
@@ -0,0 +1,4 @@
+require 'wurfl_store'
+ActionController::Base.send(:include, WurflStore::Filter)
+ActionView::Base.send(:include, WurflStore::View)
+WurflStore.init
@@ -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'
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 (zb@ubit.com)
+# 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
Oops, something went wrong.

0 comments on commit 1023636

Please sign in to comment.