browscapper 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +12 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +43 -0
- data/Rakefile +55 -0
- data/browscapper.gemspec +28 -0
- data/lib/browscapper/reader/csv_reader.rb +63 -0
- data/lib/browscapper/reader/ini_reader.rb +47 -0
- data/lib/browscapper/reader/marshal_reader.rb +13 -0
- data/lib/browscapper/reader/yaml_reader.rb +13 -0
- data/lib/browscapper/reader.rb +20 -0
- data/lib/browscapper/user_agent.rb +98 -0
- data/lib/browscapper/version.rb +6 -0
- data/lib/browscapper.rb +71 -0
- data/test/browscapper_tests.rb +57 -0
- data/test/reader_tests.rb +37 -0
- metadata +128 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 J Smith <dark.panda@gmail.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
= Browscapper
|
3
|
+
|
4
|
+
I suppose this could also be called Yet Another Browscap.ini Reader.
|
5
|
+
|
6
|
+
Browscapper.load('path/to/browscap.ini')
|
7
|
+
Browscapper.match('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8')
|
8
|
+
#=> Browscapper::UserAgent
|
9
|
+
|
10
|
+
Browscapper.matches
|
11
|
+
#=> Array of Browscapper::UserAgents, in order of best-to-worst matches.
|
12
|
+
|
13
|
+
== File Formats
|
14
|
+
|
15
|
+
The most widely used browscap.ini file is probably Gary Keith's, found at
|
16
|
+
https://browsers.garykeith.com/downloads . For the sake of convenience and
|
17
|
+
compatibiilty, Browscapper.load will look in the current directory for
|
18
|
+
a browscap.ini file. However, Browscapper can also read in browscap.csv
|
19
|
+
files as well, which are also available from Gary's site, as well as YAML
|
20
|
+
files and files written in Ruby's own Marshal'd file format. In fact, for the
|
21
|
+
sake of performance and speed, you may want to consider dumping browscap.ini
|
22
|
+
files into the Marshal'd format, which loads much faster than any of the
|
23
|
+
other file formats. For the sake of comparison, here are some benchmarks from
|
24
|
+
on my current development laptop (MacBook Pro 10,1 with a solid state drive):
|
25
|
+
|
26
|
+
bench_csv 1.111839s
|
27
|
+
bench_ini 3.801561s
|
28
|
+
bench_marshal 0.081942s
|
29
|
+
|
30
|
+
These are just the averages from a few runs, but the result is pretty clear
|
31
|
+
all the same: the Marshal'd format is by far quicker. (The YAML parser
|
32
|
+
currently has some problems with some messed up encodings and isn't
|
33
|
+
really recommended for prime time.)
|
34
|
+
|
35
|
+
To dump Browscapper into a Marshal'd format, you can either call
|
36
|
+
Browscapper.dump and write the results to a file or you can use the provided
|
37
|
+
rake task thusly:
|
38
|
+
|
39
|
+
rake browscapper:dump IN=browscap.ini OUT=browscap.dump
|
40
|
+
|
41
|
+
== License
|
42
|
+
|
43
|
+
See the MIT-LICENSE file for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
gem 'rdoc', '~> 3.12'
|
6
|
+
|
7
|
+
require 'rubygems/package_task'
|
8
|
+
require 'rake/testtask'
|
9
|
+
require 'rdoc/task'
|
10
|
+
require 'bundler/gem_tasks'
|
11
|
+
|
12
|
+
if RUBY_VERSION >= '1.9'
|
13
|
+
begin
|
14
|
+
gem 'psych'
|
15
|
+
rescue Exception => e
|
16
|
+
# it's okay, fall back on the bundled psych
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
$:.push 'lib'
|
21
|
+
|
22
|
+
version = Browscapper::VERSION
|
23
|
+
|
24
|
+
desc 'Test browscapper library'
|
25
|
+
Rake::TestTask.new(:test) do |t|
|
26
|
+
t.test_files = FileList['test/**/*_tests.rb']
|
27
|
+
t.verbose = !!ENV['VERBOSE_TESTS']
|
28
|
+
t.warning = !!ENV['WARNINGS']
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Build docs'
|
32
|
+
Rake::RDocTask.new do |t|
|
33
|
+
t.title = "browscapper #{version}"
|
34
|
+
t.main = 'README.rdoc'
|
35
|
+
t.rdoc_dir = 'doc'
|
36
|
+
t.rdoc_files.include('README.rdoc', 'MIT-LICENSE', 'lib/**/*.rb')
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Converts a browscap file to another format"
|
40
|
+
task "browscapper:dump" do
|
41
|
+
require File.join(File.dirname(__FILE__), %w{ lib browscapper })
|
42
|
+
|
43
|
+
if !ENV['IN'] || !ENV['OUT']
|
44
|
+
puts "Usage: IN=browscap OUT=browscap.dump"
|
45
|
+
puts
|
46
|
+
puts "Converts a browscap file to a ruby Marshal'd format. These files"
|
47
|
+
puts "are much quicker to load than CSV or INI files."
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
|
51
|
+
Browscapper.load(ENV['IN'])
|
52
|
+
File.open(ENV['OUT'], 'wb') do |fp|
|
53
|
+
fp.write(Marshal.dump(Browscapper.entries))
|
54
|
+
end
|
55
|
+
end
|
data/browscapper.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require File.expand_path('../lib/browscapper/version', __FILE__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = %q{browscapper}
|
7
|
+
s.version = Browscapper::VERSION
|
8
|
+
|
9
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
10
|
+
s.authors = ["J Smith"]
|
11
|
+
s.description = "A browscap file parser and matcher."
|
12
|
+
s.summary = s.description
|
13
|
+
s.email = "dark.panda@gmail.com"
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"README.rdoc"
|
16
|
+
]
|
17
|
+
s.files = `git ls-files`.split($\)
|
18
|
+
s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
19
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
20
|
+
s.homepage = "http://github.com/dark-panda/browscapper"
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_dependency("rdoc")
|
24
|
+
s.add_dependency("rake", ["~> 0.9"])
|
25
|
+
s.add_dependency("minitest")
|
26
|
+
s.add_dependency("inifile")
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
|
3
|
+
if RUBY_VERSION.to_f < 1.9
|
4
|
+
require 'fastercsv'
|
5
|
+
else
|
6
|
+
require 'csv'
|
7
|
+
end
|
8
|
+
|
9
|
+
module Browscapper
|
10
|
+
module CSVReader
|
11
|
+
CSV_ENGINE = if defined?(FasterCSV)
|
12
|
+
FasterCSV
|
13
|
+
else
|
14
|
+
CSV
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
include Reader
|
19
|
+
|
20
|
+
def load(file)
|
21
|
+
csv = CSV_ENGINE.open(file, 'rb')
|
22
|
+
|
23
|
+
# skip header
|
24
|
+
2.times { csv.shift }
|
25
|
+
headers = csv.shift
|
26
|
+
|
27
|
+
entries = Hash.new
|
28
|
+
|
29
|
+
csv.each do |l|
|
30
|
+
entry = UserAgent.new
|
31
|
+
headers.each_with_index do |v, i|
|
32
|
+
entry[v] = case l[i]
|
33
|
+
when 'false'
|
34
|
+
false
|
35
|
+
when 'true'
|
36
|
+
true
|
37
|
+
when /^\d+$/
|
38
|
+
l[i].to_i
|
39
|
+
else
|
40
|
+
l[i]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
entry.user_agent = if entry.user_agent
|
45
|
+
entry.user_agent.sub!(/^\[(.+)\]$/, '\1')
|
46
|
+
elsif entry.browser
|
47
|
+
entry.browser
|
48
|
+
end
|
49
|
+
|
50
|
+
entry.pattern = pattern_to_regexp(entry.user_agent.to_s)
|
51
|
+
|
52
|
+
if entries[entry.parent]
|
53
|
+
entry.merge!(entries[entry.parent])
|
54
|
+
end
|
55
|
+
|
56
|
+
entries[entry.user_agent] = entry
|
57
|
+
end
|
58
|
+
|
59
|
+
entries
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
|
3
|
+
require 'inifile'
|
4
|
+
|
5
|
+
module Browscapper
|
6
|
+
module INIReader
|
7
|
+
class << self
|
8
|
+
include Reader
|
9
|
+
|
10
|
+
def load(file)
|
11
|
+
ini = IniFile.load(file, :encoding => 'BINARY')
|
12
|
+
ini.delete_section('GJK_Browscap_Version')
|
13
|
+
|
14
|
+
injector = proc { |memo, section|
|
15
|
+
unless memo[section]
|
16
|
+
entry = UserAgent.new
|
17
|
+
ini[section].each do |k, v|
|
18
|
+
entry[k] = case v
|
19
|
+
when 'false'
|
20
|
+
false
|
21
|
+
when 'true'
|
22
|
+
true
|
23
|
+
when /^\d+$/
|
24
|
+
v.to_i
|
25
|
+
else
|
26
|
+
v
|
27
|
+
end
|
28
|
+
end
|
29
|
+
entry.user_agent = section
|
30
|
+
entry.pattern = pattern_to_regexp(entry.user_agent)
|
31
|
+
|
32
|
+
memo[section] = entry
|
33
|
+
|
34
|
+
if entry.parent
|
35
|
+
memo = injector.call(memo, entry.parent)
|
36
|
+
entry.merge!(memo[entry.parent])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
memo
|
41
|
+
}
|
42
|
+
|
43
|
+
ini.sections.inject({}, &injector)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
|
3
|
+
module Browscapper
|
4
|
+
module Reader
|
5
|
+
def pattern_to_regexp(pattern)
|
6
|
+
pattern = pattern.dup
|
7
|
+
|
8
|
+
if pattern.respond_to?(:force_encoding)
|
9
|
+
pattern.force_encoding('BINARY')
|
10
|
+
end
|
11
|
+
|
12
|
+
pattern.downcase!
|
13
|
+
pattern.gsub!(/([\^\$\(\)\[\]\.\-])/, "\\\\\\1")
|
14
|
+
pattern.gsub!('?', '.')
|
15
|
+
pattern.gsub!('*', '.*?')
|
16
|
+
|
17
|
+
Regexp.new("^#{pattern}$")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
|
3
|
+
module Browscapper
|
4
|
+
class UserAgent
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
ACCESSORS = [
|
8
|
+
:parent, :user_agent, :comment, :browser, :version, :major_version,
|
9
|
+
:minor_version, :platform, :platform_version, :alpha, :beta, :win16, :win32, :win64,
|
10
|
+
:frames, :iframes, :tables, :cookies, :background_sounds, :vbscript,
|
11
|
+
:javascript, :java_applets, :activex_controls, :banned, :mobile_device,
|
12
|
+
:syndication_reader, :crawler, :css_version, :aol_version, :user_agent_id,
|
13
|
+
:css, :cdf, :aol, :device_name, :device_maker, :rendering_engine_name,
|
14
|
+
:rendering_engine_version, :rendering_engine_description
|
15
|
+
]
|
16
|
+
|
17
|
+
ACCESSORS.each do |accessor|
|
18
|
+
self.class_eval do
|
19
|
+
attr_accessor accessor
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :pattern
|
24
|
+
|
25
|
+
MAP = {
|
26
|
+
'useragent' => :user_agent,
|
27
|
+
'version' => :version,
|
28
|
+
'majorver' => :major_version,
|
29
|
+
'minorver' => :minor_version,
|
30
|
+
'majorversion' => :major_version,
|
31
|
+
'minorversion' => :minor_version,
|
32
|
+
'backgroundsounds' => :background_sounds,
|
33
|
+
'javaapplets' => :java_applets,
|
34
|
+
'activexcontrols' => :activex_controls,
|
35
|
+
'isbanned' => :banned,
|
36
|
+
'ismobiledevice' => :mobile_device,
|
37
|
+
'mobiledevice' => :mobile_device,
|
38
|
+
'issyndicationreader' => :syndication_reader,
|
39
|
+
'syndicationreader' => :syndication_reader,
|
40
|
+
'cssversion' => :css_version,
|
41
|
+
'aolversion' => :aol_version,
|
42
|
+
'useragentid' => :user_agent_id,
|
43
|
+
'supportscss' => :css,
|
44
|
+
'renderingengine_name' => :rendering_engine_name,
|
45
|
+
'renderingengine_version' => :rendering_engine_version,
|
46
|
+
'renderingengine_description' => :rendering_engine_description
|
47
|
+
}
|
48
|
+
|
49
|
+
def initialize(hash = {})
|
50
|
+
self.merge!(hash)
|
51
|
+
end
|
52
|
+
|
53
|
+
def each
|
54
|
+
self.to_hash.each do |k, v|
|
55
|
+
yield k, v
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_hash
|
60
|
+
@to_hash ||= ACCESSORS.inject({}) do |memo, accessor|
|
61
|
+
memo[accessor] = self.send(accessor)
|
62
|
+
memo
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def []=(key, value)
|
67
|
+
key = key.to_s.downcase
|
68
|
+
key = "#{MAP[key] || key}="
|
69
|
+
self.send(key, value) if self.respond_to?(key)
|
70
|
+
end
|
71
|
+
|
72
|
+
def [](key)
|
73
|
+
key = key.to_s.downcase
|
74
|
+
key = MAP[key] || key
|
75
|
+
self.send(key) if self.respond_to?(key)
|
76
|
+
end
|
77
|
+
|
78
|
+
def merge!(parent)
|
79
|
+
parent = parent.to_hash if parent.is_a?(UserAgent)
|
80
|
+
ACCESSORS.each do |k, v|
|
81
|
+
if parent.has_key?(k)
|
82
|
+
val = self.send(k)
|
83
|
+
if val == 'default' || val.nil?
|
84
|
+
self.send("#{k}=", parent[k])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
self
|
89
|
+
end
|
90
|
+
|
91
|
+
def ==(other)
|
92
|
+
ACCESSORS.each do |accessor|
|
93
|
+
return false if self.send(accessor) != other.send(accessor)
|
94
|
+
end
|
95
|
+
true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/browscapper.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
|
3
|
+
module Browscapper
|
4
|
+
autoload :UserAgent, 'browscapper/user_agent'
|
5
|
+
autoload :Reader, 'browscapper/reader'
|
6
|
+
autoload :CSVReader, 'browscapper/reader/csv_reader'
|
7
|
+
autoload :YAMLReader, 'browscapper/reader/yaml_reader'
|
8
|
+
autoload :INIReader, 'browscapper/reader/ini_reader'
|
9
|
+
autoload :MarshalReader, 'browscapper/reader/marshal_reader'
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_reader :entries, :file
|
13
|
+
MATCH_CACHE = Hash.new
|
14
|
+
|
15
|
+
def load(file = File.join(%w{ . browscap.ini }))
|
16
|
+
if !File.exists?(file)
|
17
|
+
raise ArgumentError.new("File #{file} not found.")
|
18
|
+
end
|
19
|
+
|
20
|
+
reader = case file.downcase
|
21
|
+
when /\.csv$/
|
22
|
+
CSVReader
|
23
|
+
when /\.ya?ml$/
|
24
|
+
YAMLReader
|
25
|
+
when /\.ini$/
|
26
|
+
INIReader
|
27
|
+
else
|
28
|
+
MarshalReader
|
29
|
+
end
|
30
|
+
|
31
|
+
@file = file
|
32
|
+
@entries = reader.load(file)
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def dump(format = :marshal)
|
37
|
+
@entries or Browscapper.load
|
38
|
+
|
39
|
+
Marshal.dump(@entries)
|
40
|
+
end
|
41
|
+
|
42
|
+
def clear_cache
|
43
|
+
MATCH_CACHE.clear
|
44
|
+
end
|
45
|
+
|
46
|
+
def matches(ua)
|
47
|
+
@entries or self.load
|
48
|
+
|
49
|
+
ua_str = ua.downcase
|
50
|
+
ua_len = ua.length
|
51
|
+
|
52
|
+
MATCH_CACHE[ua] ||= @entries.select { |k, v|
|
53
|
+
v[:pattern] =~ ua_str if v
|
54
|
+
}.sort_by { |(k, v)|
|
55
|
+
ua_len - v[:user_agent].gsub(/[?*]/, '').length
|
56
|
+
}.collect { |(k, v)|
|
57
|
+
v
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def match(ua)
|
62
|
+
if MATCH_CACHE[ua] && !MATCH_CACHE[ua].empty?
|
63
|
+
MATCH_CACHE[ua].first
|
64
|
+
else
|
65
|
+
m = self.matches(ua)
|
66
|
+
m.first if !m.empty?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
alias :query :match
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
|
3
|
+
$: << './lib'
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require './lib/browscapper'
|
8
|
+
|
9
|
+
class BrowscapperTest < MiniTest::Unit::TestCase
|
10
|
+
FIREFOX_ON_OSX = Browscapper::UserAgent.new({
|
11
|
+
:activex_controls => false,
|
12
|
+
:alpha => false,
|
13
|
+
:aol_version => 0,
|
14
|
+
:background_sounds => false,
|
15
|
+
:beta => false,
|
16
|
+
:browser => "Firefox",
|
17
|
+
:comment => "Firefox 3.6",
|
18
|
+
:cookies => true,
|
19
|
+
:crawler => false,
|
20
|
+
:css_version => 3,
|
21
|
+
:device_name => "unknown",
|
22
|
+
:device_maker => "unknown",
|
23
|
+
:frames => true,
|
24
|
+
:iframes => true,
|
25
|
+
:java_applets => true,
|
26
|
+
:javascript => true,
|
27
|
+
:major_version => 3,
|
28
|
+
:minor_version => 6,
|
29
|
+
:mobile_device => false,
|
30
|
+
:parent => "Firefox 3.6",
|
31
|
+
:platform => "MacOSX",
|
32
|
+
:platform_version => "unknown",
|
33
|
+
:rendering_engine_name => "Gecko",
|
34
|
+
:rendering_engine_version => "unknown",
|
35
|
+
:rendering_engine_description => "For Firefox, Camino, K-Meleon, SeaMonkey, Netscape, and other Gecko-based browsers.",
|
36
|
+
:syndication_reader => false,
|
37
|
+
:tables => true,
|
38
|
+
:user_agent => "Mozilla/5.0 (Macintosh; *; *Mac OS X*; *; rv:1.9.2*) Gecko/* Firefox/3.6*",
|
39
|
+
:user_agent_id => nil,
|
40
|
+
:vbscript => false,
|
41
|
+
:version => "3.6",
|
42
|
+
:win16 => false,
|
43
|
+
:win32 => false,
|
44
|
+
:win64 => false,
|
45
|
+
})
|
46
|
+
|
47
|
+
FIREFOX_ON_OSX.pattern = /^mozilla\/5\.0 \(macintosh; .*; .*mac os x.*; .*; rv:1\.9\.2.*\) gecko\/.* firefox\/3\.6.*$/
|
48
|
+
|
49
|
+
def test_browscap_ini
|
50
|
+
Browscapper.load(File.join('vendor', 'browscap.dump'))
|
51
|
+
match = Browscapper.match('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8')
|
52
|
+
|
53
|
+
FIREFOX_ON_OSX.each do |k, v|
|
54
|
+
assert(v == match[k], " Expected #{v.inspect} for #{k}, got #{match[k].inspect}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
# encoding: BINARY
|
3
|
+
|
4
|
+
$: << './lib'
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'minitest/autorun'
|
8
|
+
require 'minitest/benchmark' if ENV['BENCH']
|
9
|
+
require './lib/browscapper'
|
10
|
+
require 'benchmark'
|
11
|
+
|
12
|
+
class ReaderTests < MiniTest::Unit::TestCase
|
13
|
+
def bench_csv
|
14
|
+
assert_performance_constant do |n|
|
15
|
+
Browscapper.load('vendor/browscap.csv')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def bench_yaml
|
20
|
+
assert_performance_constant do |n|
|
21
|
+
Browscapper.load('vendor/browscap.yml')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def bench_ini
|
26
|
+
assert_performance_constant do |n|
|
27
|
+
Browscapper.load('vendor/browscap.ini')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def bench_marshal
|
32
|
+
assert_performance_constant do |n|
|
33
|
+
Browscapper.load('vendor/browscap.dump')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: browscapper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: !binary |-
|
5
|
+
MC4wLjE=
|
6
|
+
prerelease:
|
7
|
+
platform: ruby
|
8
|
+
authors:
|
9
|
+
- J Smith
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-09-29 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rdoc
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: rake
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0.9'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0.9'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: minitest
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: inifile
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
description: A browscap file parser and matcher.
|
80
|
+
email: dark.panda@gmail.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files:
|
84
|
+
- README.rdoc
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- Gemfile
|
88
|
+
- MIT-LICENSE
|
89
|
+
- README.rdoc
|
90
|
+
- Rakefile
|
91
|
+
- browscapper.gemspec
|
92
|
+
- lib/browscapper.rb
|
93
|
+
- lib/browscapper/reader.rb
|
94
|
+
- lib/browscapper/reader/csv_reader.rb
|
95
|
+
- lib/browscapper/reader/ini_reader.rb
|
96
|
+
- lib/browscapper/reader/marshal_reader.rb
|
97
|
+
- lib/browscapper/reader/yaml_reader.rb
|
98
|
+
- lib/browscapper/user_agent.rb
|
99
|
+
- lib/browscapper/version.rb
|
100
|
+
- test/browscapper_tests.rb
|
101
|
+
- test/reader_tests.rb
|
102
|
+
homepage: http://github.com/dark-panda/browscapper
|
103
|
+
licenses: []
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 1.8.24
|
123
|
+
signing_key:
|
124
|
+
specification_version: 3
|
125
|
+
summary: A browscap file parser and matcher.
|
126
|
+
test_files:
|
127
|
+
- test/browscapper_tests.rb
|
128
|
+
- test/reader_tests.rb
|