From 1039b7a9069a87dc97f17355059a5d753fa1b5e3 Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Tue, 11 Mar 2014 10:14:28 +0100 Subject: [PATCH 1/5] Add bin/user_agent_parser script. The script reads each line from STDIN as a user agent, parses it and prints back the parsed result. --- bin/user_agent_parser | 47 +++++++++++++++++++++++++++ lib/user_agent_parser/cli.rb | 30 +++++++++++++++++ spec/cli_spec.rb | 62 ++++++++++++++++++++++++++++++++++++ user_agent_parser.gemspec | 2 +- 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100755 bin/user_agent_parser create mode 100644 lib/user_agent_parser/cli.rb create mode 100644 spec/cli_spec.rb diff --git a/bin/user_agent_parser b/bin/user_agent_parser new file mode 100755 index 0000000..3f9f1f3 --- /dev/null +++ b/bin/user_agent_parser @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby + +$: << File.expand_path('../../lib', __FILE__) + +require 'optparse' + +require 'user_agent_parser' +require 'user_agent_parser/cli' + +options = {} + +optparse = OptionParser.new do|opts| + opts.on('--name', 'Print name only') do + options[:name] = true + end + + opts.on('--version', 'Print version only') do + options[:version] = true + end + + opts.on('--major', 'Print major version only') do + options[:major] = true + end + + opts.on('--minor', 'Print minor version only') do + options[:minor] = true + end + + opts.on('--os', 'Print operating system only') do + options[:os] = true + end + + opts.on('--format format', 'Print output in specified format') do |format| + options[:format] = format + end + + opts.on('-h', '--help', 'Display this screen') do + puts opts + exit + end +end + +optparse.parse! + +ARGF.each do |line| + puts UserAgentParser::Cli.new(line, options).run! +end diff --git a/lib/user_agent_parser/cli.rb b/lib/user_agent_parser/cli.rb new file mode 100644 index 0000000..e1f2bf2 --- /dev/null +++ b/lib/user_agent_parser/cli.rb @@ -0,0 +1,30 @@ +module UserAgentParser + class Cli + def initialize(user_agent, options = {}) + @user_agent = UserAgentParser.parse(user_agent) + @options = options + end + + def run! + if @options[:name] + @user_agent.name + elsif @options[:version] + @user_agent.version.to_s + elsif @options[:major] + @user_agent.version.major + elsif @options[:minor] + @user_agent.version.minor + elsif @options[:os] + @user_agent.os.to_s + elsif format = @options[:format] + format.gsub('%n', @user_agent.name). + gsub('%v', @user_agent.version.to_s). + gsub('%M', @user_agent.version.major.to_s). + gsub('%m', @user_agent.version.minor.to_s). + gsub('%o', @user_agent.os.to_s) + else + @user_agent.to_s + end + end + end +end diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb new file mode 100644 index 0000000..1d879f6 --- /dev/null +++ b/spec/cli_spec.rb @@ -0,0 +1,62 @@ +require File.expand_path(File.dirname(__FILE__) + '/spec_helper') +require 'user_agent_parser/cli' + +describe UserAgentParser::Cli do + let(:cli) { UserAgentParser::Cli.new(user_agent, options) } + let(:options) { {} } + let(:user_agent) { + 'Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25' + } + + it 'prints name and version when no options' do + cli.run!.must_equal('Mobile Safari 6.0') + end + + describe '--name' do + let(:options) { { :name => true } } + + it 'returns name only' do + cli.run!.must_equal('Mobile Safari') + end + end + + describe '--version' do + let(:options) { { :version => true } } + + it 'returns version only' do + cli.run!.must_equal('6.0') + end + end + + describe '--major' do + let(:options) { { :major => true } } + + it 'returns major version only' do + cli.run!.must_equal('6') + end + end + + describe '--minor' do + let(:options) { { :minor => true } } + + it 'returns minor version only' do + cli.run!.must_equal('0') + end + end + + describe '--os' do + let(:options) { { :os => true } } + + it 'returns operating system only' do + cli.run!.must_equal('iOS 6.0.1') + end + end + + describe '--format' do + let(:options) { { :format => '%n|%v|%M|%m|%o' } } + + it 'return string with correct replacements' do + cli.run!.must_equal('Mobile Safari|6.0|6|0|iOS 6.0.1') + end + end +end diff --git a/user_agent_parser.gemspec b/user_agent_parser.gemspec index 22d8366..7e7c1a5 100644 --- a/user_agent_parser.gemspec +++ b/user_agent_parser.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |gem| gem.description = gem.summary gem.license = "MIT" - gem.files = %x{ git ls-files }.split("\n").select { |d| d =~ %r{^(MIT-LICENSE|Readme.md|lib/)} } + ['vendor/ua-parser/regexes.yaml'] + gem.files = %x{ git ls-files }.split("\n").select { |d| d =~ %r{^(MIT-LICENSE|Readme.md|lib|bin/)} } + ['vendor/ua-parser/regexes.yaml'] gem.required_ruby_version = '>= 1.8.7' end From 0779ad578d4b76cf001de6b26935dc5192eb883f Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Tue, 11 Mar 2014 11:42:00 +0100 Subject: [PATCH 2/5] Handle invalid version. --- lib/user_agent_parser/cli.rb | 36 ++++++++++++++++++++++++++++------ spec/cli_spec.rb | 38 ++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/lib/user_agent_parser/cli.rb b/lib/user_agent_parser/cli.rb index e1f2bf2..df49d49 100644 --- a/lib/user_agent_parser/cli.rb +++ b/lib/user_agent_parser/cli.rb @@ -9,22 +9,46 @@ def run! if @options[:name] @user_agent.name elsif @options[:version] - @user_agent.version.to_s + with_version do |version| + version.to_s + end elsif @options[:major] - @user_agent.version.major + major elsif @options[:minor] - @user_agent.version.minor + minor elsif @options[:os] @user_agent.os.to_s elsif format = @options[:format] format.gsub('%n', @user_agent.name). - gsub('%v', @user_agent.version.to_s). - gsub('%M', @user_agent.version.major.to_s). - gsub('%m', @user_agent.version.minor.to_s). + gsub('%v', version.to_s). + gsub('%M', major.to_s). + gsub('%m', minor.to_s). gsub('%o', @user_agent.os.to_s) else @user_agent.to_s end end + + private + + def major + with_version do |version| + version.major + end + end + + def minor + with_version do |version| + version.minor + end + end + + def version + @version ||= @user_agent.version + end + + def with_version(&block) + block.call(version) if version + end end end diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb index 1d879f6..1332e11 100644 --- a/spec/cli_spec.rb +++ b/spec/cli_spec.rb @@ -12,6 +12,44 @@ cli.run!.must_equal('Mobile Safari 6.0') end + describe 'invalid version' do + let(:user_agent) { + 'Mozilla/5.0 (iPad; CPU OS like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/XYZ Mobile/10A523 Safari/8536.25' + } + + describe '--version' do + let(:options) { { :version => true } } + + it 'returns nil' do + cli.run!.must_be_nil + end + end + + describe '--major' do + let(:options) { { :major => true } } + + it 'returns nil' do + cli.run!.must_be_nil + end + end + + describe '--minor' do + let(:options) { { :minor => true } } + + it 'returns nil' do + cli.run!.must_be_nil + end + end + + describe '--format' do + let(:options) { { :format => '%n|%v|%M|%m|%o' } } + + it 'returns string without versions' do + cli.run!.must_equal('Mobile Safari||||Other') + end + end + end + describe '--name' do let(:options) { { :name => true } } From 477a8c031b602865d2190f7fd9992749c056efb5 Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Wed, 12 Mar 2014 08:37:35 +0100 Subject: [PATCH 3/5] Inject user agent to avoid multiple initializations. --- bin/user_agent_parser | 4 +++- lib/user_agent_parser/cli.rb | 2 +- spec/cli_spec.rb | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/bin/user_agent_parser b/bin/user_agent_parser index 3f9f1f3..d244476 100755 --- a/bin/user_agent_parser +++ b/bin/user_agent_parser @@ -42,6 +42,8 @@ end optparse.parse! +parser = UserAgentParser::Parser.new + ARGF.each do |line| - puts UserAgentParser::Cli.new(line, options).run! + puts UserAgentParser::Cli.new(parser.parse(line), options).run! end diff --git a/lib/user_agent_parser/cli.rb b/lib/user_agent_parser/cli.rb index df49d49..9ee01af 100644 --- a/lib/user_agent_parser/cli.rb +++ b/lib/user_agent_parser/cli.rb @@ -1,7 +1,7 @@ module UserAgentParser class Cli def initialize(user_agent, options = {}) - @user_agent = UserAgentParser.parse(user_agent) + @user_agent = user_agent @options = options end diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb index 1332e11..9cea04b 100644 --- a/spec/cli_spec.rb +++ b/spec/cli_spec.rb @@ -4,8 +4,9 @@ describe UserAgentParser::Cli do let(:cli) { UserAgentParser::Cli.new(user_agent, options) } let(:options) { {} } + let(:parser) { UserAgentParser::Parser.new } let(:user_agent) { - 'Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25' + parser.parse('Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25') } it 'prints name and version when no options' do @@ -14,7 +15,7 @@ describe 'invalid version' do let(:user_agent) { - 'Mozilla/5.0 (iPad; CPU OS like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/XYZ Mobile/10A523 Safari/8536.25' + parser.parse('Mozilla/5.0 (iPad; CPU OS like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/XYZ Mobile/10A523 Safari/8536.25') } describe '--version' do From b212d0d770835c90f37785dad774867b222846d7 Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Wed, 12 Mar 2014 10:59:21 +0100 Subject: [PATCH 4/5] Document formatters in usage information. --- bin/user_agent_parser | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/user_agent_parser b/bin/user_agent_parser index d244476..d7b67ba 100755 --- a/bin/user_agent_parser +++ b/bin/user_agent_parser @@ -30,7 +30,14 @@ optparse = OptionParser.new do|opts| options[:os] = true end - opts.on('--format format', 'Print output in specified format') do |format| + opts.on('--format format', + 'Print output in specified format. The available formatters are:', + ' - %n: name', + ' - %v: version', + ' - %M: major version', + ' - %m: minor version', + ' - %o: operating system' + ) do |format| options[:format] = format end From a48d2a768f20056452e25c7e159b8d0ef110b6b0 Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Wed, 12 Mar 2014 12:20:36 +0100 Subject: [PATCH 5/5] Allow binary to be symlinked. --- bin/user_agent_parser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/user_agent_parser b/bin/user_agent_parser index d7b67ba..5c83fd4 100755 --- a/bin/user_agent_parser +++ b/bin/user_agent_parser @@ -1,6 +1,6 @@ #!/usr/bin/env ruby -$: << File.expand_path('../../lib', __FILE__) +$: << File.expand_path('../../lib', File.readlink(__FILE__)) require 'optparse'