wurfl 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.rdoc +31 -22
- data/VERSION +1 -1
- data/bin/wurfltools.rb +21 -0
- data/lib/wurfl/command.rb +4 -0
- data/lib/wurfl/command/comparator.rb +86 -0
- data/lib/wurfl/command/inspector.rb +142 -0
- data/lib/wurfl/command/loader.rb +129 -0
- data/lib/wurfl/command/sanitycheck.rb +40 -0
- data/lib/wurfl/command/uaproftowurfl.rb +28 -0
- data/lib/wurfl/command/uaprofwurflcomparator.rb +224 -0
- data/wurfl.gemspec +12 -9
- metadata +12 -15
- data/bin/uaproftowurfl.rb +0 -28
- data/bin/uaprofwurflcomparator.rb +0 -223
- data/bin/wurflcomparator.rb +0 -86
- data/bin/wurflinspector.rb +0 -141
- data/bin/wurflloader.rb +0 -127
- data/bin/wurflsanitycheck.rb +0 -39
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -6,14 +6,16 @@ WURFL is a collection of libraries and command line tools for using and manipula
|
|
6
6
|
|
7
7
|
== Tools
|
8
8
|
|
9
|
-
|
9
|
+
All tools are run via wurfltools.rb
|
10
|
+
|
11
|
+
=== loader
|
10
12
|
|
11
13
|
Is used to parse and load a WURFL XML file into memory or save a
|
12
14
|
PStore database that is used by most of the other tools. This
|
13
15
|
application creates WURFL PStore databases that are essential for use
|
14
16
|
with the other Ruby applications.
|
15
17
|
|
16
|
-
===
|
18
|
+
=== inspector
|
17
19
|
|
18
20
|
Is a tool that will let you do various searches and queries on the
|
19
21
|
WURFL. This is a very simple, yet powerful program for finding
|
@@ -24,12 +26,15 @@ examples section for usage.
|
|
24
26
|
|
25
27
|
The command below will search through all handsets and return the ids
|
26
28
|
of handsets that match the passed Ruby boolean evaluation
|
27
|
-
|
28
|
-
|
29
|
+
|
30
|
+
This command will return all handsets that have more than 2 colors.
|
31
|
+
|
32
|
+
wurfltools.rb inspector -d pstorehandsets.db -s '{ |hand| hand["colors"].to_i > 2 }'"
|
33
|
+
|
29
34
|
The Ruby query must go in between the single quote marks and needs to
|
30
35
|
declare the WurflHandset instance variable name.
|
31
36
|
|
32
|
-
|
37
|
+
This command shows you how you can cheat with the current design of
|
33
38
|
the wurflinspector and print more user friendly results. This example
|
34
39
|
assumes you have the command line programs sort and uniq, but that is
|
35
40
|
only to make the output look better. This example does the same as the
|
@@ -37,24 +42,27 @@ above, except that it prints out the brand name and model name of the
|
|
37
42
|
matching handsets instead of the WURFL id.
|
38
43
|
|
39
44
|
Note: this should all go into one command line call
|
40
|
-
|
41
|
-
|
42
|
-
|
45
|
+
|
46
|
+
wurfltools.rb inspector -d pstorehandsets.db -s '{|hand| puts
|
47
|
+
"#{hand["brand_name"]} #{hand["model_name"]}" if hand["colors"].to_i >
|
48
|
+
2}' | sort | uniq"
|
43
49
|
|
44
50
|
|
45
51
|
The following individual handset query commands will tell the value of
|
46
52
|
capabilities and from where it obtained the setting.
|
47
53
|
|
48
|
-
|
54
|
+
A command to query the handset with the id sonyericsson_t300_ver1
|
49
55
|
for all of its' capabilities:
|
50
|
-
"wurflinspector.rb -d pstorehandsets.db -i sonyericsson_t300_ver1"
|
51
56
|
|
52
|
-
|
57
|
+
wurfltools.rb inspector -d pstorehandsets.db -i sonyericsson_t300_ver1
|
58
|
+
|
59
|
+
A command to query the handset with the id sonyericsson_t300_ver1 for
|
53
60
|
backlight capability:
|
54
|
-
"wurflinspector.rb -d pstorehandsets.db -i sonyericsson_t300_ver1 -q
|
55
|
-
backlight"
|
56
61
|
|
57
|
-
|
62
|
+
wurfltools.rb inspector -d pstorehandsets.db -i sonyericsson_t300_ver1 -q
|
63
|
+
backlight
|
64
|
+
|
65
|
+
=== sanitycheck
|
58
66
|
|
59
67
|
Is a partial WURFL validating program. It does a few simple
|
60
68
|
checks to make sure the XML structure is parse-able by the wurflloader.
|
@@ -62,14 +70,14 @@ If you receive loading errors by the wurflloader, then you can run the
|
|
62
70
|
wurflsanitycheck program to find the lines in the XML file that might
|
63
71
|
be causing the problem.
|
64
72
|
|
65
|
-
===
|
73
|
+
=== comparator
|
66
74
|
|
67
75
|
Is a another simple program that will find the differences from two
|
68
76
|
WURFL Ruby PStore databases. This is another way of finding changes
|
69
77
|
from the different versions of the WURFL without running a diff on the
|
70
78
|
XML files.
|
71
79
|
|
72
|
-
=== uaproftowurfl
|
80
|
+
=== uaproftowurfl
|
73
81
|
|
74
82
|
Is a program that takes UAProfiles and creates an equivalent WURFL
|
75
83
|
entry. It holds all of the mappings used to convert a UAProfile to a
|
@@ -97,12 +105,12 @@ the UAProfToWurfl class later.
|
|
97
105
|
|
98
106
|
A simple usage is:
|
99
107
|
|
100
|
-
|
108
|
+
wurfltools.rb uaproftowurfl sampleprofile.xml
|
101
109
|
|
102
110
|
Example use from a bash shell with many profiles:
|
103
111
|
|
104
112
|
for i in `ls profiles`; do
|
105
|
-
|
113
|
+
wurfltools.rb uaproftowurfl profiles/$i >output/$i.wurfl
|
106
114
|
2> output/$i.parser.err;
|
107
115
|
done
|
108
116
|
|
@@ -110,7 +118,7 @@ This assumes that you have a profiles directory with all of the UAProf
|
|
110
118
|
file you wish to parse and a output directory to place the results and
|
111
119
|
errors.
|
112
120
|
|
113
|
-
=== uaprofwurflcomparator
|
121
|
+
=== uaprofwurflcomparator
|
114
122
|
|
115
123
|
Is a program that compares UAProfiles against the equivalent WURFL
|
116
124
|
entries. It takes a file that contains an UAProfile URL and an
|
@@ -126,12 +134,13 @@ from the given URL, a file that holds the UAProfil URL and User-Agent
|
|
126
134
|
mappings, and the Ruby PStore database that holds the WURFL.
|
127
135
|
|
128
136
|
The following is a simple example of execution
|
129
|
-
|
137
|
+
|
138
|
+
wurfltools.rb uaprofwurflcomparator -d ./profiles -f all-profile.2003-08.log -c -w wurfl.db
|
130
139
|
|
131
140
|
== Authors
|
132
141
|
|
133
|
-
Zev Blut (Original Author)
|
134
|
-
Paul McMahon (gem installer, refactorings)
|
142
|
+
* Zev Blut (Original Author)
|
143
|
+
* Paul McMahon (gem installer, refactorings)
|
135
144
|
|
136
145
|
== Copyright
|
137
146
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
data/bin/wurfltools.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
|
5
|
+
def usage
|
6
|
+
puts "usage: wurfltools.rb command options"
|
7
|
+
path = "#{File.dirname(__FILE__)}/../lib/wurfl/command/*"
|
8
|
+
a = Dir.glob(path).map {|s| File.basename(s,".rb")}
|
9
|
+
puts "available commands:"
|
10
|
+
puts a
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
|
14
|
+
usage if ARGV.size < 1
|
15
|
+
|
16
|
+
command = ARGV.shift
|
17
|
+
|
18
|
+
require "wurfl/command/#{command}"
|
19
|
+
|
20
|
+
c = Wurfl::Command.const_get(command.capitalize).new
|
21
|
+
c.execute
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "wurfl/command"
|
2
|
+
require "getoptlong"
|
3
|
+
require "wurfl/handset"
|
4
|
+
require "wurfl/utils"
|
5
|
+
|
6
|
+
class Wurfl::Command::Comparator < Wurfl::Command
|
7
|
+
include Wurfl::Utils
|
8
|
+
|
9
|
+
def usage
|
10
|
+
puts "Usage: wurfltools.rb comparator wurfl_pstore1_db wurfl_pstore2_db "
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute
|
15
|
+
if ARGV.size != 2
|
16
|
+
usage
|
17
|
+
end
|
18
|
+
|
19
|
+
# load the wurfl databases
|
20
|
+
wurfl1 = wurfl2 = nil
|
21
|
+
begin
|
22
|
+
wurfl1, = load_wurfl_pstore(ARGV[0])
|
23
|
+
wurfl2, = load_wurfl_pstore(ARGV[1])
|
24
|
+
rescue => err
|
25
|
+
efile = ""
|
26
|
+
if wurfl1.nil?
|
27
|
+
efile = ARGV[0]
|
28
|
+
else
|
29
|
+
efile = ARGV[1]
|
30
|
+
end
|
31
|
+
STDERR.puts "Error with file #{efile}"
|
32
|
+
STDERR.puts err.message
|
33
|
+
exit 1
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "Comparing files: #{ARGV[0]} and #{ARGV[1]}"
|
37
|
+
puts "-------------------------------------"
|
38
|
+
|
39
|
+
if wurfl1.size > wurfl2.size
|
40
|
+
mwurfl = wurfl1
|
41
|
+
lwurfl = wurfl2
|
42
|
+
else
|
43
|
+
mwurfl = wurfl2
|
44
|
+
lwurfl = wurfl1
|
45
|
+
end
|
46
|
+
|
47
|
+
notfound = Array.new
|
48
|
+
different = Array.new
|
49
|
+
mwurfl.each do |key,handset|
|
50
|
+
if lwurfl.key?(key)
|
51
|
+
if handset != lwurfl[key]
|
52
|
+
different<< [handset,lwurfl[key]]
|
53
|
+
end
|
54
|
+
else
|
55
|
+
notfound<< handset
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
puts "Comparision complete."
|
61
|
+
|
62
|
+
puts "Not Found Handsets: #{notfound.size}"
|
63
|
+
puts "||||||||||||||||||||||||||||||||||||"
|
64
|
+
notfound = notfound.sort { |x,y| y.wurfl_id <=> x.wurfl_id }
|
65
|
+
notfound.each { |hand| puts hand.wurfl_id }
|
66
|
+
puts "||||||||||||||||||||||||||||||||||||"
|
67
|
+
|
68
|
+
puts "Different handsets: #{different.size}"
|
69
|
+
puts "||||||||||||||||||||||||||||||||||||"
|
70
|
+
different = different.sort { |x,y| y.first.wurfl_id <=> x.first.wurfl_id }
|
71
|
+
different.each do |hand1,hand2|
|
72
|
+
puts "-------------------------------------"
|
73
|
+
puts "Handset: #{hand1.user_agent} :ID: #{hand1.wurfl_id}"
|
74
|
+
diffkeys = hand1.compare(hand2)
|
75
|
+
diffkeys.each do |key,oval,oid|
|
76
|
+
next if hand1[key].nil? || hand2[key].nil?
|
77
|
+
puts "Key:#{key}"
|
78
|
+
puts "h1>:#{hand1[key]}"
|
79
|
+
puts "h2<:#{hand2[key]}"
|
80
|
+
end
|
81
|
+
puts "-------------------------------------"
|
82
|
+
end
|
83
|
+
|
84
|
+
puts "||||||||||||||||||||||||||||||||||||"
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require "wurfl/command"
|
2
|
+
|
3
|
+
require "getoptlong"
|
4
|
+
require "wurfl/handset"
|
5
|
+
require "wurfl/utils"
|
6
|
+
|
7
|
+
class Wurfl::Command::Inspector < Wurfl::Command
|
8
|
+
=begin
|
9
|
+
A class that lists wurfl handsets that match user specified search
|
10
|
+
criteria.
|
11
|
+
=end
|
12
|
+
class WurflInspector
|
13
|
+
|
14
|
+
# Constructor
|
15
|
+
# Parameters:
|
16
|
+
# handsets: A hashtable of wurfl handsets indexed by wurfl_id.
|
17
|
+
def initialize(handsets)
|
18
|
+
@handsets = handsets
|
19
|
+
end
|
20
|
+
|
21
|
+
# A method to get the WurflHandset that matches the passed wurfl_id.
|
22
|
+
# Parameters:
|
23
|
+
# id: is the wurfl_id of the WurflHandset to get.
|
24
|
+
# Returns:
|
25
|
+
# The WurflHandset that has the requested wurfl_id. If the wurfl_id
|
26
|
+
# is not found, then nil is returned.
|
27
|
+
def get_handset(id)
|
28
|
+
return @handsets[id]
|
29
|
+
end
|
30
|
+
|
31
|
+
# A method to retrieve a list of the inspector's handsets that match
|
32
|
+
# the passed search criteria.
|
33
|
+
# Parameters:
|
34
|
+
# proc: is a Proc object that defines a function that returns
|
35
|
+
# true or false from an evaluattion with a WurflHandset.
|
36
|
+
# Returns:
|
37
|
+
# An Array of all WurflHandsets that match the proc evaluation.
|
38
|
+
def search_handsets(proc)
|
39
|
+
rez = @handsets.values.select do |hand|
|
40
|
+
x = proc.call(hand)
|
41
|
+
end
|
42
|
+
return rez if rez != nil
|
43
|
+
return Array::new
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
include Wurfl::Utils
|
50
|
+
|
51
|
+
def usage
|
52
|
+
puts "Usage: wurfltools.rb inspector [-s rubyblock] [-i handsetid [-q attributename]] -d pstorefile"
|
53
|
+
puts "Examples:"
|
54
|
+
puts "wurfltools.rb inspector -d pstorehandsets.db -s '{ |hand| hand[\"colors\"].to_i > 2 }'"
|
55
|
+
puts "wurfltools inspector -d pstorehandsets.db -i sonyericsson_t300_ver1"
|
56
|
+
puts "wurfltools inspector -d pstorehandsets.db -i sonyericsson_t300_ver1 -q backlight"
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
|
60
|
+
def execute
|
61
|
+
pstorefile = nil
|
62
|
+
procstr = nil
|
63
|
+
handset = nil
|
64
|
+
query = nil
|
65
|
+
begin
|
66
|
+
opt = GetoptLong.new(
|
67
|
+
["-d","--database", GetoptLong::REQUIRED_ARGUMENT],
|
68
|
+
["-s","--search", GetoptLong::REQUIRED_ARGUMENT],
|
69
|
+
["-i","--id", GetoptLong::REQUIRED_ARGUMENT],
|
70
|
+
["-q","--query", GetoptLong::REQUIRED_ARGUMENT]
|
71
|
+
)
|
72
|
+
|
73
|
+
opt.each do |arg,val|
|
74
|
+
case arg
|
75
|
+
when "-d"
|
76
|
+
pstorefile = val
|
77
|
+
when "-s"
|
78
|
+
procstr = val.strip
|
79
|
+
when "-i"
|
80
|
+
handset = val
|
81
|
+
when "-q"
|
82
|
+
query = val
|
83
|
+
else
|
84
|
+
usage
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
rescue => err
|
89
|
+
usage
|
90
|
+
end
|
91
|
+
|
92
|
+
if !pstorefile
|
93
|
+
puts "You must specify a Wurfl PStore db"
|
94
|
+
usage
|
95
|
+
end
|
96
|
+
|
97
|
+
begin
|
98
|
+
handsets, = load_wurfl_pstore(pstorefile)
|
99
|
+
insp = WurflInspector.new(handsets)
|
100
|
+
rescue => err
|
101
|
+
STDERR.puts "Error with file #{pstorefile}"
|
102
|
+
STDERR.puts err.message
|
103
|
+
exit 1
|
104
|
+
end
|
105
|
+
|
106
|
+
if procstr
|
107
|
+
pr = nil
|
108
|
+
eval("pr = proc#{procstr}")
|
109
|
+
|
110
|
+
if pr.class != Proc
|
111
|
+
puts "You must pass a valid ruby block!"
|
112
|
+
exit 1
|
113
|
+
end
|
114
|
+
|
115
|
+
puts "--------- Searching handsets -----------"
|
116
|
+
res = insp.search_handsets(pr)
|
117
|
+
puts "Number of results: #{res.size}"
|
118
|
+
|
119
|
+
res.each { |handset| puts handset.wurfl_id }
|
120
|
+
exit 0
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
if handset
|
125
|
+
handset = insp.get_handset(handset)
|
126
|
+
puts "Handset user agent: #{handset.user_agent}"
|
127
|
+
if query
|
128
|
+
puts "Result of handset query: #{query}"
|
129
|
+
rez = handset.get_value_and_owner(query)
|
130
|
+
puts "#{rez[0]} from #{rez[1]}"
|
131
|
+
else
|
132
|
+
puts "Attributes of handset"
|
133
|
+
keys = handset.keys
|
134
|
+
keys.each do |key|
|
135
|
+
rez = handset.get_value_and_owner(key)
|
136
|
+
puts "Attr:#{key} Val:#{rez[0]} from #{rez[1]}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
exit 0
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require "wurfl/command"
|
2
|
+
|
3
|
+
require "getoptlong"
|
4
|
+
require "wurfl/utils"
|
5
|
+
require "wurfl/loader"
|
6
|
+
|
7
|
+
class Wurfl::Command::Loader < Wurfl::Command
|
8
|
+
include Wurfl::Utils
|
9
|
+
|
10
|
+
def usage
|
11
|
+
puts "Usage: wurfltools.rb loader [-p -v -h -e patchfile] -f wurflfile"
|
12
|
+
puts " --file, -f (wurflfile): The master WURFL file to load."
|
13
|
+
puts " --extension, -e (patchfile): A patch file to extend the traits of the master WURLF file."
|
14
|
+
puts " --print, -p : Prints out handsets."
|
15
|
+
puts " --verbose, -v : Verbose output."
|
16
|
+
puts " --help, -h : Prints this message."
|
17
|
+
puts " --database, -d (databasename): Makes a PStore database for quick loading of data with other tools."
|
18
|
+
puts " --load, -l (databasename): Loads handsets from a PStore database instead of XML file."
|
19
|
+
exit 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute
|
23
|
+
print = false
|
24
|
+
insert = false
|
25
|
+
verbose = false
|
26
|
+
wurflfile = nil
|
27
|
+
patchfile = nil
|
28
|
+
pstorefile = nil
|
29
|
+
pstoreload = false
|
30
|
+
|
31
|
+
begin
|
32
|
+
options = GetoptLong.new(
|
33
|
+
["-p","--print", GetoptLong::NO_ARGUMENT],
|
34
|
+
["-h","--help", GetoptLong::NO_ARGUMENT],
|
35
|
+
["-v","--verbose", GetoptLong::NO_ARGUMENT],
|
36
|
+
["-f","--file", GetoptLong::REQUIRED_ARGUMENT],
|
37
|
+
["-e","--extension", GetoptLong::REQUIRED_ARGUMENT],
|
38
|
+
["-d","--database", GetoptLong::REQUIRED_ARGUMENT],
|
39
|
+
["-l","--load", GetoptLong::REQUIRED_ARGUMENT]
|
40
|
+
)
|
41
|
+
|
42
|
+
options.each do |opt,arg|
|
43
|
+
case opt
|
44
|
+
when "-p"
|
45
|
+
print = true
|
46
|
+
when "-v"
|
47
|
+
verbose = true
|
48
|
+
when "-h"
|
49
|
+
usage
|
50
|
+
exit 1
|
51
|
+
when "-f"
|
52
|
+
wurflfile = arg
|
53
|
+
when "-e"
|
54
|
+
patchfile = arg
|
55
|
+
when "-d"
|
56
|
+
pstorefile = arg
|
57
|
+
when "-l"
|
58
|
+
pstorefile = arg
|
59
|
+
pstoreload = true
|
60
|
+
else
|
61
|
+
STDERR.puts "Unknown argument #{opt}"
|
62
|
+
usage
|
63
|
+
exit 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
rescue => err
|
67
|
+
STDERR.puts "Error: #{err}"
|
68
|
+
usage
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
wurfll = Wurfl::Loader.new
|
73
|
+
hands = nil
|
74
|
+
fallbacks = nil
|
75
|
+
|
76
|
+
if pstorefile && pstoreload
|
77
|
+
begin
|
78
|
+
puts "Loading data from #{pstorefile}"
|
79
|
+
hands, fallbacks = load_wurfl_pstore(pstorefile)
|
80
|
+
puts "Loaded"
|
81
|
+
rescue => err
|
82
|
+
STDERR.puts "Error: Cannot load PStore file."
|
83
|
+
STDERR.puts err.message
|
84
|
+
exit 1
|
85
|
+
end
|
86
|
+
else
|
87
|
+
if !wurflfile
|
88
|
+
STDERR.puts "You must pass a wurflfile if you want to do more."
|
89
|
+
usage
|
90
|
+
exit 1
|
91
|
+
end
|
92
|
+
|
93
|
+
starttime = Time.now
|
94
|
+
puts "Loading wurfl file #{wurflfile}"
|
95
|
+
|
96
|
+
wurfll.verbose = verbose
|
97
|
+
|
98
|
+
hands, fallbacks = wurfll.load_wurfl(wurflfile)
|
99
|
+
restime = Time.now - starttime
|
100
|
+
|
101
|
+
puts "Done loading wurfl. Load took #{restime} seconds."
|
102
|
+
|
103
|
+
if patchfile
|
104
|
+
starttime = Time.now
|
105
|
+
puts "Loading Patch file #{patchfile}"
|
106
|
+
hands, fallbacks = wurfll.load_wurfl(patchfile)
|
107
|
+
restime = Time.now - starttime
|
108
|
+
puts "Done loading patchfile. Load took #{restime} seconds."
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
if pstorefile && !pstoreload
|
114
|
+
begin
|
115
|
+
puts "Saving data into #{pstorefile}"
|
116
|
+
save_wurfl_pstore(pstorefile, hands, fallbacks)
|
117
|
+
puts "Saved"
|
118
|
+
rescue => err
|
119
|
+
STDERR.puts "Error: Cannot creat PStore file."
|
120
|
+
STDERR.puts err.message
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
if print
|
125
|
+
wurfll.print_wurfl hands
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|