Skip to content

Commit

Permalink
Allow passing multiple pattern databases as an array to the new `patt…
Browse files Browse the repository at this point in the history
…ern_paths` argument

- Support `patterns_path` argument but deprecate `pattern_path` attribute accessor
- Add new `patterns_paths` array argument to enable loading multiple patterns files

Fixes #11
  • Loading branch information
Mikhail Doronin authored and misdoro committed Dec 24, 2021
1 parent dc9c41b commit e1348e5
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 9 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ or when instantiating a `UserAgentParser::Parser`:
UserAgentParser::Parser.new(patterns_path: '/some/path/to/regexes.yaml').parse(ua_string)
```

It is also possible to specify multiple patterns paths if you want to add some custom patterns without forking the main database:
```ruby
UserAgentParser::Parser.new(patterns_paths: [UserAgentParser::DefaultPatternsPath, '/some/path/to/regexes.yaml'])
```

## Command line tool

The gem incldes a `user_agent_parser` bin command which will read from
Expand Down
31 changes: 26 additions & 5 deletions lib/user_agent_parser/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

module UserAgentParser
class Parser
extend Gem::Deprecate

FAMILY_REPLACEMENT_KEYS = %w[
family_replacement
v1_replacement
Expand All @@ -22,11 +24,15 @@ class Parser

private_constant :FAMILY_REPLACEMENT_KEYS, :OS_REPLACEMENT_KEYS

attr_reader :patterns_path
attr_reader :patterns_paths

def initialize(patterns_path: nil, patterns_paths: [])
@patterns_paths = [patterns_path, *patterns_paths].compact
if @patterns_paths.empty?
@patterns_paths = [UserAgentParser::DefaultPatternsPath]
end

def initialize(patterns_path: nil)
@patterns_path = patterns_path || UserAgentParser::DefaultPatternsPath
@ua_patterns, @os_patterns, @device_patterns = load_patterns(@patterns_path)
@ua_patterns, @os_patterns, @device_patterns = load_patterns(@patterns_paths)
end

def parse(user_agent)
Expand All @@ -35,9 +41,24 @@ def parse(user_agent)
parse_ua(user_agent, os, device)
end

def patterns_path
patterns_paths.first
end
deprecate :patterns_path, :patterns_paths, 2020, 12

private

def load_patterns(path)
def load_patterns(patterns_paths)
patterns_paths.inject([[], [], []]) do |patterns, path|
ua_patterns, os_patterns, device_patterns = load_patterns_file(path)
patterns[0] += ua_patterns
patterns[1] += os_patterns
patterns[2] += device_patterns
patterns
end
end

def load_patterns_file(path)
yml = YAML.load_file(path)

# Parse all the regexs
Expand Down
6 changes: 3 additions & 3 deletions spec/custom_regexes.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
user_agent_parsers:
- regex: '.*'
- regex: 'Any.*'
family_replacement: 'Custom browser'
v1_replacement: '1'
v2_replacement: '2'
v3_replacement: '3'
v4_replacement: '4'

os_parsers:
- regex: '.*'
- regex: 'Any.*'
os_replacement: 'Custom OS'
os_v1_replacement: '1'
os_v2_replacement: '2'

device_parsers:
- regex: '.*'
- regex: 'Any.*'
device_replacement: 'Custom device'
17 changes: 17 additions & 0 deletions spec/other_regexes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
user_agent_parsers:
- regex: 'Other.*'
family_replacement: 'Other browser'
v1_replacement: '1'
v2_replacement: '2'
v3_replacement: '3'
v4_replacement: '4'

os_parsers:
- regex: 'Other.*'
os_replacement: 'Other OS'
os_v1_replacement: '1'
os_v2_replacement: '2'

device_parsers:
- regex: 'Other.*'
device_replacement: 'Other device'
16 changes: 15 additions & 1 deletion spec/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ def custom_patterns_path
File.join(File.dirname(__FILE__), 'custom_regexes.yaml')
end

def other_patterns_path
File.join(File.dirname(__FILE__), 'other_regexes.yaml')
end

describe '::parse' do
it 'parses a UA' do
ua = UserAgentParser.parse('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3')
Expand All @@ -69,7 +73,7 @@ def custom_patterns_path
end

describe '#initialize with a custom patterns path' do
it 'uses the custom patterns' do
it 'accepts a single pattern_path' do
parser = UserAgentParser::Parser.new(patterns_path: custom_patterns_path)
ua = parser.parse('Any user agent string')

Expand All @@ -85,6 +89,16 @@ def custom_patterns_path

_(ua.device.family).must_equal('Custom device')
end

it 'accepts pattern_paths array' do
parser = UserAgentParser::Parser.new(patterns_paths: [custom_patterns_path, other_patterns_path])

ua = parser.parse('Any user agent string')
oua = parser.parse('Other user agent string')

_(ua.family).must_equal('Custom browser')
_(oua.family).must_equal('Other browser')
end
end

describe '#parse' do
Expand Down

0 comments on commit e1348e5

Please sign in to comment.