pod_ident 1.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.
- checksums.yaml +7 -0
- data/.circleci/config.yml +52 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +20 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +44 -0
- data/README.md +80 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/parse-rules +8 -0
- data/bin/setup +8 -0
- data/lib/detection_rules.yml +978 -0
- data/lib/pod_ident/detection_result.rb +24 -0
- data/lib/pod_ident/detection_rules.rb +3 -0
- data/lib/pod_ident/rule_parser.rb +60 -0
- data/lib/pod_ident/version.rb +5 -0
- data/lib/pod_ident.rb +108 -0
- data/pod_ident.gemspec +33 -0
- metadata +134 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PodIdent
|
|
4
|
+
class DetectionResult
|
|
5
|
+
attr_reader :app, :user_agent, :rule
|
|
6
|
+
attr_accessor :platform
|
|
7
|
+
|
|
8
|
+
def initialize(rule, user_agent)
|
|
9
|
+
@user_agent = user_agent
|
|
10
|
+
return unless rule
|
|
11
|
+
|
|
12
|
+
@rule = rule
|
|
13
|
+
@app = rule[:app]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def positive?
|
|
17
|
+
!@app.nil?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def platform_rule
|
|
21
|
+
@rule[:platform]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
# DO NOT EDIT THIS FILE - it gets automatically generated by running "bin/parse-rules"
|
|
2
|
+
|
|
3
|
+
RULES = [{:app=>"Apple Podcasts", :match=>{"startsWith"=>"AppleCoreMedia"}, :platform=>{"regex"=>"\\((\\w+\\s*\\w*)", "replacements"=>[{"name"=>"Macintosh", "replaceWith"=>"Mac"}]}}, {:app=>"Apple Podcasts", :match=>{"startsWith"=>"itunesstored"}, :platform=>{"regex"=>"(iPad|iPod|iPhone)"}}, {:app=>"iTunes", :match=>{"startsWith"=>"iTunes", "excluding"=>{"regex"=>"Downcast|iCatcher|SqueezeCenter|SqueezeNetwork|MusicServer"}}, :platform=>{"regex"=>"\\((\\w+\\s*\\w*)", "replacements"=>[{"name"=>"Macintosh", "replaceWith"=>"Mac"}]}}, {:app=>"Apple Podcasts", :match=>{"includes"=>"watchOS"}, :platform=>{"text"=>"watchOS"}}, {:app=>"CastBox", :match=>{"startsWith"=>["CastBox", "Castbox"]}, :platform=>{"regexes"=>["(Android|iOS|OS\\sVersion)", "(CastBox)"], "replacements"=>[{"name"=>"OS Version", "replaceWith"=>"iOS"}, {"name"=>"CastBox", "replaceWith"=>"Android"}]}}, {:app=>"Amazon Alexa", :match=>{"startsWith"=>"Alexa"}, :platform=>{"text"=>"Alexa-capable device"}}, {:app=>"Amazon Alexa", :match=>{"startsWith"=>"Echo"}, :platform=>{"text"=>"Amazon Echo", "userAgents"=>[{"userAgent"=>"Echo/1.0(APNG)", "platform"=>"Amazon Echo"}]}}, {:app=>"Deezer", :match=>{"startsWith"=>"Deezer"}, :platform=>{"regexes"=>["(Android|Darwin)", "\\((\\w+\\s*\\w*)"], "replacements"=>[{"name"=>"osx", "replaceWith"=>"Mac"}, {"name"=>"Darwin", "replaceWith"=>"Apple Device"}]}}, {:app=>"Overcast", :match=>{"startsWith"=>"Overcast"}, :platform=>{"text"=>"iOS"}}, {:app=>"Radio.net", :match=>{"startsWith"=>["radio.net", "radio.de", "radio.at", "radio.fr", "radio.dk", "radio.es", "radio.it", "radio.pt", "radio.pl"]}, :platform=>{"regex"=>"(Android|Darwin)", "replacements"=>[{"name"=>"Darwin", "replaceWith"=>"iOS"}]}}, {:app=>"PocketCasts", :match=>{"startsWith"=>["PocketCasts", "Pocket Casts", "Shifty Jelly Pocket Casts"]}, :platform=>{"regex"=>"(Android)"}}, {:app=>"Himalaya", :match=>{"startsWith"=>"Himalaya"}, :platform=>{"regex"=>"(Darwin|Android)", "replacements"=>[{"name"=>"Darwin", "replaceWith"=>"iOS"}]}}, {:app=>"ExoPlayer", :match=>{"startsWith"=>["ExoPlayer", "yourApplicationName", "null", "md5d42223d6ee7473da82e8136ffb794439.App"]}, :platform=>{"text"=>"Android"}}, {:app=>"Download Manager", :match=>{"startsWith"=>"AndroidDownloadManager"}, :platform=>{"text"=>"Android"}}, {:app=>"Castamatic", :match=>{"startsWith"=>"Castamatic"}, :platform=>{"text"=>"iOS"}}, {:app=>"The Podcast App (podcast.app)", :match=>{"includes"=>"The Podcast App"}, :platform=>{"text"=>"iOS"}}, {:app=>"CastMix", :match=>{"startsWith"=>"CastMix"}, :platform=>{"text"=>"Android"}}, {:app=>"Unknown App", :match=>{"startsWith"=>"okhttp"}, :platform=>{"text"=>"Android"}}, {:app=>"Stagefright Media Playback Engine", :match=>{"includes"=>"stagefright", "excluding"=>{"text"=>"stagefright alternative"}}, :platform=>{"regex"=>"(Fire OS|Android)"}}, {:app=>"LG Player", :match=>{"startsWith"=>"Player/LG Player", "includes"=>["LG Player", "LG-Player"]}, :platform=>{"text"=>"Android"}}, {:app=>"Android Browser", :match=>{"startsWith"=>"Dalvik"}, :platform=>{"text"=>"Android"}}, {:app=>"Acast", :match=>{"startsWith"=>"Acast"}, :platform=>{"regex"=>"(Darwin|Android|Windows)", "replacements"=>[{"name"=>"Darwin", "replaceWith"=>"iOS"}]}}, {:app=>"Castro", :match=>{"startsWith"=>"Castro"}, :platform=>{"text"=>"iOS"}}, {:app=>"Breaker", :match=>{"startsWith"=>"Breaker"}, :platform=>{"regex"=>"(Darwin|Android)", "replacements"=>[{"name"=>"Darwin", "replaceWith"=>"iOS"}]}}, {:app=>"Podcast Addict", :match=>{"startsWith"=>["PodcastAddict", "Podcast Addict"]}, :platform=>{"text"=>"Android"}}, {:app=>"Podbean", :match=>{"startsWith"=>"Podbean"}, :platform=>{"regex"=>"(iOS|Android)"}}, {:app=>"Google Podcasts", :match=>{"includes"=>["GSA"], "excluding"=>{"regex"=>"iPhone|iPad"}}, :platform=>{"text"=>"Android"}}, {:app=>"Google Search App", :match=>{"includes"=>["GSA"], "excluding"=>{"regex"=>"Android"}}, :platform=>{"regexes"=>["(iPhone|iPad)"]}}, {:app=>"Google Podcasts", :match=>{"includes"=>"GoogleChirp"}, :platform=>{"text"=>"Google Smart Speaker"}}, {:app=>"Stitcher", :match=>{"startsWith"=>"Stitcher"}, :platform=>{"regex"=>"(iOS|Android)"}}, {:app=>"TuneIn", :match=>{"startsWith"=>"TuneIn"}, :platform=>{"regex"=>"(Darwin|Android)", "replacements"=>[{"name"=>"Darwin", "replaceWith"=>"iOS"}]}}, {:app=>"PodCruncher", :match=>{"startsWith"=>"PodCruncher"}, :platform=>{"text"=>"iOS"}}, {:app=>"iCatcher!", :match=>{"startsWith"=>"iCatcher!", "includes"=>"iCatcher!"}, :platform=>{"regex"=>"\\((iPhone|iPad|iPod touch)", "fallback"=>"iOS"}}, {:app=>"Castaway", :match=>{"startsWith"=>"Castaway"}, :platform=>{"text"=>"iOS"}}, {:app=>"Instacast", :match=>{"startsWith"=>"Instacast"}, :platform=>{"text"=>"Apple Device"}}, {:app=>"VLC", :match=>{"startsWith"=>["VLC", "LibVLC"], "includes"=>"VLC"}, :platform=>{"regex"=>"(Android|iPhone)"}}, {:app=>"Podcast Republic", :match=>{"startsWith"=>"PodcastRepublic"}, :platform=>{"text"=>"Android"}}, {:app=>"DoggCatcher", :match=>{"includes"=>"DoggCatcher"}, :platform=>{"text"=>"Android"}}, {:app=>"Player FM", :match=>{"startsWith"=>["Player FM", "Player%20FM"]}, :platform=>{"regex"=>"(Darwin)", "fallback"=>"Android", "replacements"=>[{"name"=>"Darwin", "replaceWith"=>"iOS"}]}}, {:app=>"Podkicker", :match=>{"startsWith"=>"Podkicker"}, :platform=>{"text"=>"Android"}}, {:app=>"AntennaPod", :match=>{"startsWith"=>"AntennaPod"}, :platform=>{"text"=>"Android"}}, {:app=>"Downcast", :match=>{"startsWith"=>"Downcast", "includes"=>"Downcast"}, :platform=>{"regex"=>"\\((iPhone|iPad|iPod touch|Mac)"}}, {:app=>"gPodder", :match=>{"startsWith"=>"gPodder"}, :platform=>{"regex"=>"(Linux|Windows)"}}, {:app=>"Podcatcher Deluxe", :match=>{"includes"=>"Podcatcher Deluxe"}, :platform=>{"text"=>"Android"}}, {:app=>"Procast", :match=>{"startsWith"=>["Procast", "ProCast"]}, :platform=>{"text"=>"iOS"}}, {:app=>"RSSRadio", :match=>{"startsWith"=>"RSSRadio"}, :platform=>{"regex"=>"(iPhone|iPad|iPod touch|Darwin)", "replacements"=>[{"name"=>"Darwin", "replaceWith"=>"iOS"}], "fallback"=>"iOS"}}, {:app=>"Podcat", :match=>{"startsWith"=>"Podcat", "excluding"=>{"regex"=>"Podcatcher"}}, :platform=>{"text"=>"iOS"}}, {:app=>"Audio Now", :match=>{"startsWith"=>"AudioNow", "includes"=>"audionow"}, :platform=>{"regex"=>"(iOS|Android)"}}, {:app=>"DIE ZEIT App", :match=>{"includes"=>"ZONApp"}, :platform=>{"regex"=>"(iPhone|iPad|iPod touch|Android)"}}, {:app=>"F.A.Z Der Tag App", :match=>{"includes"=>"FAZDERTAG"}, :platform=>{"regexes"=>["(Android)", "\\((iPhone|iPad|iPod touch)"]}}, {:app=>"ANTENNE BAYERN App", :match=>{"includes"=>"AntenneBayern"}, :platform=>{"regexes"=>["(Android)", "\\((iPhone|iPad|iPod touch)"]}}, {:app=>"BuzzFeed App", :match=>{"includes"=>"buzzfeed"}, :platform=>{"regexes"=>["(Android)", "\\((iPhone|iPad|iPod touch)"]}}, {:app=>"Facebook in-app browser", :match=>{"includes"=>["FBAN", "FBAV"]}, :platform=>{"regexes"=>["\\((iPhone|iPad|iPod touch)", "(Android)"]}}, {:app=>"Instagram in-app browser", :match=>{"includes"=>"Instagram"}, :platform=>{"regexes"=>["(iPad)", "(iPhone|Android)"]}}, {:app=>"Twitter in-app browser", :match=>{"includes"=>"Twitter"}, :platform=>{"regex"=>"(iPhone|iPad|Darwin|Android)", "replacements"=>[{"name"=>"Darwin", "replaceWith"=>"Apple device"}]}}, {:app=>"Pinterest in-app browser", :match=>{"includes"=>"Pinterest"}, :platform=>{"regexes"=>["(Android)", "\\((iPhone|iPad|iPod touch)"]}}, {:app=>"Windows Media Player", :match=>{"startsWith"=>["NSPlayer", "WMPlayer"]}, :platform=>{"text"=>"Windows"}}, {:app=>"Sonos", :match=>{"includes"=>"Sonos"}, :platform=>{"text"=>"Sonos"}}, {:app=>"Internet Explorer", :match=>{"includes"=>"Trident"}, :platform=>{"regex"=>"(Windows Phone)", "fallback"=>"Windows"}}, {:app=>"Kodi Media Center", :match=>{"startsWith"=>"Kodi", "includes"=>"Kodi"}, :platform=>{"regex"=>"(X11|Android|Windows)", "replacements"=>[{"name"=>"X11", "replaceWith"=>"Linux"}]}}, {:app=>"HermesPod", :match=>{"startsWith"=>"+hermespod.com"}, :platform=>{"text"=>"Windows"}}, {:app=>"ViennaRSS", :match=>{"includes"=>"Vienna"}, :platform=>{"text"=>"Mac"}}, {:app=>"Unknown client", :match=>{"startsWith"=>"(null)"}, :platform=>{"regex"=>"(iPhone|iPad|iPod touch)"}}, {:app=>"Clementine Music Player", :match=>{"startsWith"=>"Clementine"}, :platform=>{"text"=>"Unknown"}}, {:app=>"Flipboard", :match=>{"includes"=>"Flipboard"}, :platform=>{"regexes"=>["(Android)", "\\((iPhone|iPad|iPod touch|Macintosh)"], "replacements"=>[{"name"=>"Macintosh", "replaceWith"=>"Mac"}]}}, {:app=>"iVoox", :match=>{"startsWith"=>["ivoox", "iVoox"]}, :platform=>{"regexes"=>["(Android)", "(Darwin)\\/", "\\((iPhone|iPad|iPod touch|Macintosh)"], "replacements"=>[{"name"=>"Darwin", "replaceWith"=>"Apple device"}, {"name"=>"Macintosh", "replaceWith"=>"Mac"}]}}, {:app=>"FYEO", :match=>{"startsWith"=>"FYEO"}, :platform=>{"regex"=>"(iOS|Android)"}}].freeze
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require 'pry'
|
|
5
|
+
|
|
6
|
+
module PodIdent
|
|
7
|
+
class RuleParser
|
|
8
|
+
RULES_YAML = File.expand_path('../detection_rules.yml', __dir__)
|
|
9
|
+
RULES_RUBY = File.expand_path('detection_rules.rb', __dir__)
|
|
10
|
+
RULES_SPEC_RUBY = File.expand_path('../../spec/detection_rules.rb', __dir__)
|
|
11
|
+
DO_NOT_EDIT_TEXT = <<~HEREDOC
|
|
12
|
+
# DO NOT EDIT THIS FILE - it gets automatically generated by running \"bin/parse-rules\"\n
|
|
13
|
+
HEREDOC
|
|
14
|
+
|
|
15
|
+
attr_accessor :rules
|
|
16
|
+
|
|
17
|
+
def call
|
|
18
|
+
parse_yaml
|
|
19
|
+
write_rules_rb
|
|
20
|
+
write_rules_spec_rb
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def write_rules_rb
|
|
26
|
+
cleaned_rules = rules.dup.map do |rule|
|
|
27
|
+
{
|
|
28
|
+
app: rule['app'],
|
|
29
|
+
match: rule['match'],
|
|
30
|
+
platform: rule['platform']
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
File.open(RULES_RUBY, 'w') do |file|
|
|
35
|
+
file.write(DO_NOT_EDIT_TEXT)
|
|
36
|
+
file.write("RULES = #{cleaned_rules}.freeze")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def write_rules_spec_rb
|
|
41
|
+
all_rules = rules.dup.map do |rule|
|
|
42
|
+
# symbolize keys
|
|
43
|
+
Hash[rule.map { |(k, v)| [k.to_sym, v] }]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
File.open(RULES_SPEC_RUBY, 'w') do |file|
|
|
47
|
+
file.write(DO_NOT_EDIT_TEXT)
|
|
48
|
+
file.write("RULES = #{all_rules}.freeze")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def parse_yaml
|
|
53
|
+
@rules = YAML.safe_load(rules_yaml_file_content)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def rules_yaml_file_content
|
|
57
|
+
File.read(RULES_YAML).gsub('\\\\', '\\')
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/pod_ident.rb
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pod_ident/version'
|
|
4
|
+
require 'pod_ident/detection_rules'
|
|
5
|
+
require 'pod_ident/detection_result'
|
|
6
|
+
|
|
7
|
+
module PodIdent
|
|
8
|
+
class Detector
|
|
9
|
+
attr_reader :user_agent_string
|
|
10
|
+
attr_accessor :result
|
|
11
|
+
|
|
12
|
+
def self.detect(user_agent_string)
|
|
13
|
+
new(user_agent_string).detect
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(user_agent_string)
|
|
17
|
+
@user_agent_string = user_agent_string
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def detect
|
|
21
|
+
# !~ /[^[:space:]]/ is what Active Support does to detect blank strings
|
|
22
|
+
return nil if user_agent_string !~ /[^[:space:]]/
|
|
23
|
+
|
|
24
|
+
self.result = DetectionResult.new(find_rule, user_agent_string)
|
|
25
|
+
identify_platform if result.positive?
|
|
26
|
+
|
|
27
|
+
result
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def find_rule
|
|
33
|
+
RULES.detect do |rule|
|
|
34
|
+
found = false
|
|
35
|
+
|
|
36
|
+
match = rule.fetch(:match)
|
|
37
|
+
|
|
38
|
+
found = apply_starts_with(match['startsWith'], found)
|
|
39
|
+
found ||= apply_includes(match['includes'], found)
|
|
40
|
+
|
|
41
|
+
excluding = match['excluding']
|
|
42
|
+
if found && excluding
|
|
43
|
+
found = false if excluding['text'] && user_agent_string.include?(excluding['text'])
|
|
44
|
+
|
|
45
|
+
if excluding['regex'] && Regexp.new(excluding['regex']).match(user_agent_string)
|
|
46
|
+
found = false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
found
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def apply_starts_with(starts_with, found)
|
|
55
|
+
return found unless starts_with
|
|
56
|
+
|
|
57
|
+
Array(starts_with).detect do |string|
|
|
58
|
+
found = user_agent_string.start_with?(string)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
found
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def apply_includes(includes, found)
|
|
65
|
+
return found unless includes
|
|
66
|
+
|
|
67
|
+
Array(includes).detect do |string|
|
|
68
|
+
found = user_agent_string.include?(string)
|
|
69
|
+
end
|
|
70
|
+
found
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def identify_platform
|
|
74
|
+
result.platform = nil
|
|
75
|
+
|
|
76
|
+
regexes = if result.platform_rule['regex']
|
|
77
|
+
Array(result.platform_rule['regex'])
|
|
78
|
+
else
|
|
79
|
+
result.platform_rule['regexes']
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
result.platform = result.platform_rule['text'] if result.platform_rule['text']
|
|
83
|
+
|
|
84
|
+
regexes&.detect do |regex|
|
|
85
|
+
match = Regexp.new(regex).match(user_agent_string)
|
|
86
|
+
next if match.nil?
|
|
87
|
+
|
|
88
|
+
result.platform = match[1]
|
|
89
|
+
if result.platform_rule['replacements']
|
|
90
|
+
result.platform = replace_name(result.platform, result.platform_rule['replacements'])
|
|
91
|
+
end
|
|
92
|
+
true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
result.platform = result.platform_rule['fallback'] if !result.platform && result.platform_rule['fallback']
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def replace_name(target, replacements)
|
|
99
|
+
replacement = replacements.detect { |repl| repl['name'] == target }
|
|
100
|
+
|
|
101
|
+
if replacement
|
|
102
|
+
replacement['replaceWith']
|
|
103
|
+
else
|
|
104
|
+
target
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
data/pod_ident.gemspec
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
+
require 'pod_ident/version'
|
|
6
|
+
|
|
7
|
+
Gem::Specification.new do |spec|
|
|
8
|
+
spec.name = 'pod_ident'
|
|
9
|
+
spec.version = PodIdent::VERSION
|
|
10
|
+
spec.authors = ['Podigee GmbH']
|
|
11
|
+
spec.email = ['hello@podigee.com']
|
|
12
|
+
|
|
13
|
+
spec.summary = 'Identifies podcast client user agents'
|
|
14
|
+
spec.description = <<~HEREDOC
|
|
15
|
+
Library to identify podcast client user agents and translate them into human readable information.'
|
|
16
|
+
HEREDOC
|
|
17
|
+
spec.homepage = 'https://www.podigee.com'
|
|
18
|
+
|
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
21
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
23
|
+
end
|
|
24
|
+
spec.bindir = 'exe'
|
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
26
|
+
spec.require_paths = ['lib']
|
|
27
|
+
|
|
28
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
|
29
|
+
spec.add_development_dependency 'pry'
|
|
30
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
|
31
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
32
|
+
spec.add_development_dependency 'rspec_junit_formatter'
|
|
33
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: pod_ident
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Podigee GmbH
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2020-03-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.16'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.16'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: pry
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '13.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '13.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rspec
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rspec_junit_formatter
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
description: 'Library to identify podcast client user agents and translate them into
|
|
84
|
+
human readable information.''
|
|
85
|
+
|
|
86
|
+
'
|
|
87
|
+
email:
|
|
88
|
+
- hello@podigee.com
|
|
89
|
+
executables: []
|
|
90
|
+
extensions: []
|
|
91
|
+
extra_rdoc_files: []
|
|
92
|
+
files:
|
|
93
|
+
- ".circleci/config.yml"
|
|
94
|
+
- ".gitignore"
|
|
95
|
+
- ".rspec"
|
|
96
|
+
- ".rubocop.yml"
|
|
97
|
+
- ".ruby-version"
|
|
98
|
+
- Gemfile
|
|
99
|
+
- Gemfile.lock
|
|
100
|
+
- README.md
|
|
101
|
+
- Rakefile
|
|
102
|
+
- bin/console
|
|
103
|
+
- bin/parse-rules
|
|
104
|
+
- bin/setup
|
|
105
|
+
- lib/detection_rules.yml
|
|
106
|
+
- lib/pod_ident.rb
|
|
107
|
+
- lib/pod_ident/detection_result.rb
|
|
108
|
+
- lib/pod_ident/detection_rules.rb
|
|
109
|
+
- lib/pod_ident/rule_parser.rb
|
|
110
|
+
- lib/pod_ident/version.rb
|
|
111
|
+
- pod_ident.gemspec
|
|
112
|
+
homepage: https://www.podigee.com
|
|
113
|
+
licenses: []
|
|
114
|
+
metadata: {}
|
|
115
|
+
post_install_message:
|
|
116
|
+
rdoc_options: []
|
|
117
|
+
require_paths:
|
|
118
|
+
- lib
|
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
|
+
requirements:
|
|
126
|
+
- - ">="
|
|
127
|
+
- !ruby/object:Gem::Version
|
|
128
|
+
version: '0'
|
|
129
|
+
requirements: []
|
|
130
|
+
rubygems_version: 3.0.3
|
|
131
|
+
signing_key:
|
|
132
|
+
specification_version: 4
|
|
133
|
+
summary: Identifies podcast client user agents
|
|
134
|
+
test_files: []
|