brauser 3.3.2 → 4.0.0

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/.travis-gemfile +4 -5
  4. data/.travis.yml +2 -2
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile +7 -8
  7. data/README.md +31 -95
  8. data/Rakefile +0 -1
  9. data/brauser.gemspec +4 -4
  10. data/default_definitions/browsers.rb +50 -0
  11. data/default_definitions/languages.rb +118 -0
  12. data/default_definitions/platforms.rb +24 -0
  13. data/doc/Brauser.html +6 -6
  14. data/doc/Brauser/Browser.html +3867 -580
  15. data/doc/Brauser/Definitions.html +537 -0
  16. data/doc/Brauser/Definitions/Base.html +342 -0
  17. data/doc/Brauser/Definitions/Browser.html +1047 -0
  18. data/doc/Brauser/Definitions/Language.html +496 -0
  19. data/doc/Brauser/Definitions/Platform.html +686 -0
  20. data/doc/Brauser/Hooks.html +2 -2
  21. data/doc/Brauser/Hooks/RubyOnRails.html +9 -9
  22. data/doc/Brauser/Parser.html +513 -0
  23. data/doc/Brauser/Value.html +601 -0
  24. data/doc/Brauser/Version.html +5 -5
  25. data/doc/_index.html +25 -108
  26. data/doc/class_list.html +1 -1
  27. data/doc/file.README.html +33 -97
  28. data/doc/index.html +33 -97
  29. data/doc/method_list.html +72 -120
  30. data/doc/top-level-namespace.html +2 -2
  31. data/lib/brauser.rb +13 -15
  32. data/lib/brauser/browser.rb +195 -66
  33. data/lib/brauser/definitions/base.rb +71 -0
  34. data/lib/brauser/definitions/browser.rb +80 -0
  35. data/lib/brauser/definitions/language.rb +29 -0
  36. data/lib/brauser/definitions/platform.rb +42 -0
  37. data/lib/brauser/hooks.rb +1 -2
  38. data/lib/brauser/parser.rb +47 -0
  39. data/lib/brauser/value.rb +39 -0
  40. data/lib/brauser/version.rb +3 -4
  41. data/spec/brauser/browser_spec.rb +73 -564
  42. data/spec/brauser/default_definitions_spec.rb +129 -0
  43. data/spec/brauser/definitions/base_spec.rb +48 -0
  44. data/spec/brauser/definitions/browser_spec.rb +47 -0
  45. data/spec/brauser/definitions/language_spec.rb +18 -0
  46. data/spec/brauser/definitions/platform_spec.rb +36 -0
  47. data/spec/brauser/hooks_spec.rb +5 -6
  48. data/spec/brauser/parser_spec.rb +31 -0
  49. data/spec/brauser/value_spec.rb +34 -0
  50. data/spec/coverage_helper.rb +0 -1
  51. data/spec/spec_helper.rb +0 -1
  52. metadata +50 -23
  53. data/lib/brauser/browseable/attributes.rb +0 -95
  54. data/lib/brauser/browseable/general.rb +0 -104
  55. data/lib/brauser/browseable/parsing.rb +0 -127
  56. data/lib/brauser/browseable/partial_querying.rb +0 -116
  57. data/lib/brauser/browseable/querying.rb +0 -63
  58. data/lib/brauser/browseable/register.rb +0 -73
  59. data/lib/brauser/definition.rb +0 -80
  60. data/lib/brauser/definitions/browsers.rb +0 -68
  61. data/lib/brauser/definitions/languages.rb +0 -130
  62. data/lib/brauser/definitions/platforms.rb +0 -30
  63. data/lib/brauser/query.rb +0 -36
  64. data/lib/brauser/queryable/chainers.rb +0 -56
  65. data/lib/brauser/queryable/queries.rb +0 -60
  66. data/spec/brauser/definition_spec.rb +0 -39
  67. data/spec/brauser/query_spec.rb +0 -111
@@ -103,9 +103,9 @@
103
103
  </div>
104
104
 
105
105
  <div id="footer">
106
- Generated on Thu May 22 12:11:27 2014 by
106
+ Generated on Mon Sep 29 16:43:31 2014 by
107
107
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
108
- 0.8.7.4 (ruby-2.1.2).
108
+ 0.8.7.4 (ruby-2.1.3).
109
109
  </div>
110
110
 
111
111
  </body>
@@ -1,26 +1,24 @@
1
- # encoding: utf-8
2
1
  #
3
2
  # This file is part of the brauser gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
4
3
  # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
4
  #
6
5
 
7
6
  require "lazier"
7
+ require "versionomy"
8
8
 
9
- Lazier.load!(:object, :boolean)
9
+ ::I18n.enforce_available_locales = false
10
+ Lazier.load!(:object, :boolean, :string)
10
11
 
11
12
  require "brauser/version" unless defined?(Brauser::Version)
12
- require "brauser/queryable/chainers"
13
- require "brauser/queryable/queries"
14
- require "brauser/query"
15
- require "brauser/definitions/browsers"
16
- require "brauser/definitions/languages"
17
- require "brauser/definitions/platforms"
18
- require "brauser/definition"
19
- require "brauser/browseable/attributes"
20
- require "brauser/browseable/general"
21
- require "brauser/browseable/parsing"
22
- require "brauser/browseable/partial_querying"
23
- require "brauser/browseable/querying"
24
- require "brauser/browseable/register"
13
+ require "brauser/definitions/base"
14
+ require "brauser/definitions/browser"
15
+ require "brauser/definitions/language"
16
+ require "brauser/definitions/platform"
17
+ require "brauser/value"
18
+ require "brauser/parser"
25
19
  require "brauser/browser"
26
20
  require "brauser/hooks"
21
+
22
+ require __dir__ + "/../default_definitions/browsers"
23
+ require __dir__ + "/../default_definitions/platforms"
24
+ require __dir__ + "/../default_definitions/languages"
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  #
3
2
  # This file is part of the brauser gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
4
3
  # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
@@ -12,95 +11,225 @@ module Brauser
12
11
  # @return [String] The raw User-Agent HTTP header.
13
12
  # @attribute accept_language
14
13
  # @return [String] The raw Accept-Language HTTP header.
15
- # @attribute languages
16
- # @return [Array] The accepted languages.
17
- # @attribute name
18
- # @return [String] The current browser name.
19
- # @attribute version
20
- # @return [String] The current browser version.
21
- # @attribute platform
22
- # @return [String] The current browser platform.
14
+ # @attribute [r] name
15
+ # @return [Symbol] The current browser name.
16
+ # @attribute [r] human_name
17
+ # @return [String] The human-readable current browser name.
18
+ # @attribute [r] version
19
+ # @return [Versionomy::Value] The current browser version.
20
+ # @attribute [r] platform
21
+ # @return [Symbol] The current browser platform.
22
+ # @attribute [r] human_platform
23
+ # @return [String] The human-readable current browser platform.
24
+ # @attribute [r] languages
25
+ # @return [Hash] The accepted languages.
26
+ # @attribute [r] human_languages
27
+ # @return [Hash] The human-readable list of accepted languages.
23
28
  class Browser
24
- attr_accessor :agent
25
- attr_accessor :accept_language
26
- attr_accessor :languages
27
- attr_accessor :name
28
- attr_accessor :version
29
- attr_accessor :platform
30
-
31
- # Aliases
29
+ attr_accessor :agent, :accept_language
30
+ attr_reader :name, :human_name, :version, :platform, :human_platform, :languages, :human_languages
32
31
  alias_attribute :ua, :agent
33
32
 
34
- include ::Brauser::Browseable::General
35
- include ::Brauser::Browseable::Attributes
36
- include ::Brauser::Browseable::DefaultDefinitions
37
- include ::Brauser::Browseable::Register
38
- include ::Brauser::Browseable::Parsing
39
- include ::Brauser::Browseable::PartialQuerying
40
- include ::Brauser::Browseable::Querying
41
-
42
33
  # Creates a new browser.
43
34
  #
44
35
  # @param agent [String] The User-Agent HTTP header.
45
36
  # @param accept_language [String] The Accept-Language HTTP header.
46
37
  def initialize(agent = "", accept_language = "")
47
- ::Brauser::Browser.add_default_browsers
48
- ::Brauser::Browser.add_default_platforms
49
- ::Brauser::Browser.add_default_languages
50
-
51
38
  @agent = agent
52
39
  @accept_language = accept_language
53
-
54
- @languages = parse_accept_language(@accept_language) if @accept_language
55
- parse_agent(@agent) if @agent
56
- end
57
-
58
- # Get the current browser version (if called without arguments) or checks if the browser is a specific version.
59
- #
60
- # @see #is_version
61
- # @param versions [String|Hash] A string in the form `operator version && ...` (example: `>= 7 && < 4`) or an hash with specific version to match against,
62
- # in form `{:operator => version}`, where operator is one of `:lt, :lte, :eq, :gt, :gte`.
63
- # @return [String|Query] The browser version or a query which can evaluated for concatenation or result.
64
- def version(versions = nil)
65
- !versions ? @version : version_equals_to(versions)
40
+ parse
66
41
  end
67
42
 
68
- # This method enables the use of dynamic queries in just one method.
43
+ # Returns an array of information about the browser. Information are strings which are suitable to use as CSS classes.
69
44
  #
70
- # For example:
45
+ # For version, it will be included a class for every token of the version. For example, version `7.0.1.2` will return this:
71
46
  #
72
47
  # ```ruby
73
- # browser.is_msie_v_gt_4_1_on_windows?
74
- # #=> true
48
+ # ["version-7", "version-7_0", "version-7_0_1", "version-7_0_1_2"]
75
49
  # ```
76
50
  #
77
- # If you don't provide a trailing `?`, you will get a Brauser::Query.
51
+ # If you provide a block (with accepts name, version and platform as arguments), it will be used for translating the name.
78
52
  #
79
- # If the syntax is invalid, a `NoMethodError` exception will be raised.
53
+ # @param join [String|NilClass] If non falsy, the separator to use to join information. If falsy, informations will be returned as array.
54
+ # @param name [Boolean] If non falsy, the string to prepend to the name. If falsy, the name information will not be included.
55
+ # @param version [String|NilClass] If non falsy, the string to prepend to the version. If falsy, the version information will not be included.
56
+ # @param platform [String|NilClass] If non falsy, the string to prepend to the platform. If falsy, the platform information will not be included.
57
+ # @return [String|Array] CSS ready information of the current browser.
58
+ def classes(join = " ", name: true, version: true, platform: true)
59
+ rv = [name_to_str(name), version_to_str(version), platform_to_str(platform)].compact.uniq.flatten
60
+ join ? rv.join(join) : rv
61
+ end
62
+ alias_method :meta, :classes
63
+ alias_method :to_s, :classes
64
+
65
+ # Checks if the browser accepts a specific language or languages.
80
66
  #
81
- # @param query [String] The query to issue. Use `_` in place of `.` in the version.
82
- # @param arguments [Array] The arguments to pass the method. Unused from the query.
83
- # @param block [Proc] A block to pass to the method. Unused from the query.
84
- # @return [Boolean|Query|nil] A query or a boolean value (if `method` ends with `?`). If the query is not valid, `NoMethodError` will be raised.
85
- def method_missing(query, *arguments, &block)
86
- query_s = query.ensure_string
87
- rv = execute_query(parse_query(query_s)) || Brauser::Query.new(self, false)
88
- query_s =~ /\?$/ ? rv.result : rv
89
- rescue NoMethodError
90
- super(query, *arguments, &block)
67
+ # @param languages [Array] The list of languages.
68
+ # @return [Boolean] `true` if at least one of requested languages is accepted, `false` otherwise.
69
+ def accepts?(*languages)
70
+ languages = normalize_query_arguments(languages)
71
+ (@languages.keys & languages).present?
91
72
  end
92
73
 
93
- private
74
+ # Checks if the browser matches a specific query.
75
+ #
76
+ # @param name [Symbol|Array] The list of names to check. Also, this meta-name is supported: `:tablet`.
77
+ # @param engine [Symbol|Array] Alias for `name`, **which has precedence over this.**
78
+ # @param version [String] The query to match the version.
79
+ # It must be a query in the form is `OPERATOR VALUE && ..`, where `OPERATOR` is one of `["<", "<=", "=", "==", ">=", ">"]`.
80
+ # You can also pass the value "capable", which will return true for Webkit browsers, IE 10 or above, Firefox 28 and above and Opera 15 and above.
81
+ # @param platform [Symbol|Array] The list of platforms to check.
82
+ # @param languages [Symbol|Array] The list of languages to check.
83
+ # @return [Boolean] `true` if browser match the query, `false` otherwise.
84
+ def is?(name: nil, engine: nil, version: nil, platform: nil, languages: nil)
85
+ name ||= engine
86
+ rv = name ? (@name == apply_aliases(normalize_query_arguments(name))) : true
87
+ rv &&= query_version(version) if version
88
+ rv &&= @platform == normalize_query_arguments(platform) if platform
89
+ rv &&= accepts?(normalize_query_arguments(languages)) if languages
90
+ rv
91
+ end
94
92
 
95
- # Executes a parsed query
93
+ # Check if the browser is a specific one
96
94
  #
97
- # @param query [Array] And array of `[method, arguments]` entries.
98
- # @return [Brauser::Query] The result of the query.
99
- def execute_query(query)
100
- query.reduce(Brauser::Query.new(self, true)) { |rv, call|
101
- break unless rv.result
102
- rv.send(call[0], *call[1])
95
+ # @param method The browser engine to check.
96
+ # @param args [Array] **unused.**
97
+ # @param block [Proc] **unused.**
98
+ # @return [Boolean] `true` if browser match the engine, `false` otherwise.
99
+ def method_missing(method, *args, &block)
100
+ method.to_s =~ /(.+)\?$/ ? is?(name: Regexp.last_match[1]) : super(method, *args, &block)
101
+ end
102
+
103
+ private
104
+
105
+ # :nodoc:
106
+ VERSION_TOKEN = /(?<operator>>=|<=|<|>|!=|(={1,2}))\s*(?<version>.+)/
107
+
108
+ # :nodoc:
109
+ def parse
110
+ parser = Brauser::Parser.new
111
+ parse_agent(parser)
112
+ parse_languages(parser)
113
+ end
114
+
115
+ # :nodoc:
116
+ def parse_agent(parser)
117
+ agent = parser.parse_agent(@agent)
118
+
119
+ if agent
120
+ @name, @version, @platform = *agent
121
+ @human_name = Brauser::Definitions.browsers[@name].try(:name) || "Unknown Browser"
122
+ @human_platform = Brauser::Definitions.platforms[@platform].try(:name) || "Unknown Platform"
123
+ else
124
+ @name = @platform = Brauser::Value.new(:unknown)
125
+ @human_name = @human_platform = Brauser::Value.new("Unknown")
126
+ @version = Brauser::Value.new(Versionomy.parse("0.0"))
127
+ end
128
+ end
129
+
130
+ # :nodoc:
131
+ def parse_languages(parser)
132
+ languages = parser.parse_accept_language(@accept_language)
133
+ @languages = languages
134
+ @human_languages = languages.reduce({}) { |rv, (code, priority)|
135
+ rv[Brauser::Definitions.languages[code].name] = priority
136
+ rv
103
137
  }
104
138
  end
139
+
140
+ # :nodoc:
141
+ def name_to_str(name)
142
+ if name
143
+ name = "" if name.is_a?(TrueClass)
144
+ rv = @name
145
+ rv = [:msie_compatibility, :msie] if rv == :msie_compatibility
146
+ rv.ensure_array(no_duplicates: true) { |n| "#{name}#{n}" }
147
+ else
148
+ nil
149
+ end
150
+ end
151
+
152
+ # :nodoc:
153
+ def version_to_str(version)
154
+ if version
155
+ version = "version-" if version.is_a?(TrueClass)
156
+ version_str = @version.values_array.reduce([]) { |rv, current|
157
+ rv << [rv.last, current].compact.join("_")
158
+ rv
159
+ }
160
+
161
+ version_str.map { |v| "#{version}#{v}" }
162
+ else
163
+ nil
164
+ end
165
+ end
166
+
167
+ # :nodoc:
168
+ def platform_to_str(platform)
169
+ if platform
170
+ platform = "platform-" if platform.is_a?(TrueClass)
171
+ "#{platform}#{@platform}"
172
+ else
173
+ nil
174
+ end
175
+ end
176
+
177
+ # :nodoc:
178
+ def normalize_query_arguments(arguments)
179
+ sanitizer = ->(a) { a.ensure_string.downcase.gsub("_", "-").to_sym }
180
+ arguments ? arguments.ensure_array(no_duplicates: true, compact: true, flatten: true, &sanitizer) : nil
181
+ end
182
+
183
+ # :nodoc:
184
+ def apply_aliases(names)
185
+ names << [:msie, :msie_compatibility] if (names & [:ie, :msie]).present?
186
+ names << [:chromium] if names.include?(:chrome)
187
+ names << [:ipad, :android, :kindle] if names.include?(:tablet)
188
+ names.flatten.compact.uniq
189
+ end
190
+
191
+ # :nodoc:
192
+ def query_version(version)
193
+ version.ensure_string.strip.parameterize.to_sym == :capable ? check_capable_browser : check_version(version)
194
+ end
195
+
196
+ # :nodoc:
197
+ def check_version(version)
198
+ parser = StringScanner.new(version)
199
+ rv = true
200
+
201
+ until parser.eos?
202
+ token = parser.scan_until(/(?=&&)|\Z/)
203
+ parser.skip_until(/&&|\Z/)
204
+ operator, version = parse_version_token(token)
205
+
206
+ rv &&= @version.send(operator, Versionomy.parse(version))
207
+ break unless rv
208
+ end
209
+
210
+ rv
211
+ end
212
+
213
+ # :nodoc:
214
+ def check_capable_browser
215
+ check_capable_browser_engines || check_capable_browser_recents
216
+ end
217
+
218
+ # :nodoc:
219
+ def check_capable_browser_engines
220
+ chrome? || safari? || check_capable_browser_recents
221
+ end
222
+
223
+ # :nodoc:
224
+ def check_capable_browser_recents
225
+ (firefox? && @version >= "28") || (msie? && @version >= "10") || (opera? && @version >= "15")
226
+ end
227
+
228
+ # :nodoc:
229
+ def parse_version_token(token)
230
+ mo = VERSION_TOKEN.match(token)
231
+ raise ArgumentError, "Invalid version check: #{token}." unless mo
232
+ [mo["operator"], mo["version"]].map(&:strip)
233
+ end
105
234
  end
106
235
  end
@@ -0,0 +1,71 @@
1
+ #
2
+ # This file is part of the brauser gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Brauser
7
+ # Definitions used by brauser.
8
+ module Definitions
9
+ # Registers a new definition.
10
+ #
11
+ # @param type [Symbol] The type of the definition. Can be `:browser`, `:language`, `:platform`.
12
+ # @param args [Array] The arguments of the definition.
13
+ # @param kwargs [Hash] The keyword arguments of the definition.
14
+ # @param block [Proc] The block of the definition.
15
+ def self.register(type, *args, **kwargs, &block)
16
+ klass =
17
+ case type
18
+ when :browser then Brauser::Definitions::Browser
19
+ when :language then Brauser::Definitions::Language
20
+ when :platform then Brauser::Definitions::Platform
21
+ else raise(ArgumentError, "Invalid definition type \"#{type}\".")
22
+ end
23
+
24
+ @definitions ||= {browsers: {}, languages: {}, platforms: {}}
25
+ definition = klass.new(*args, **kwargs, &block)
26
+ @definitions["#{type}s".to_sym][definition.id] = definition
27
+ end
28
+
29
+ # Returns the list of browser that can be recognized.
30
+ #
31
+ # The keys are the ids, the values are the definitions.
32
+ #
33
+ # @return [Hash] The list of browser that can be recognized.
34
+ def self.browsers
35
+ @definitions[:browsers]
36
+ end
37
+
38
+ # Returns the list of platforms that can be recognized.
39
+ #
40
+ # The keys are the ids, the values are the definitions.
41
+ #
42
+ # @return [Hash] The list of platform that can be recognized.
43
+ def self.platforms
44
+ @definitions[:platforms]
45
+ end
46
+
47
+ # Returns the list of languages that can be recognized.
48
+ #
49
+ # The keys are the ids, the values are the definitions.
50
+ #
51
+ # @return [Hash] The list of languages that can be recognized.
52
+ def self.languages
53
+ @definitions[:languages]
54
+ end
55
+
56
+ # A class which hold a definition of a browser, a platform or a language.
57
+ #
58
+ # @attribute [r] id
59
+ # @return The id of the definition.
60
+ class Base
61
+ attr_reader :id
62
+
63
+ # Performs a match of this definition.
64
+ #
65
+ # @return [Object|NilClass] A non falsy value if match succeeded, `false` or `nil` otherwise.
66
+ def match(_, *_, **_)
67
+ raise "Must be overridden by a subclass."
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,80 @@
1
+ #
2
+ # This file is part of the brauser gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Brauser
7
+ module Definitions
8
+ # A definition of a platform.
9
+ #
10
+ # @attribute [r] name
11
+ # @return [String] The platform name.
12
+ # @attribute [r] engine_matcher
13
+ # @return [Regexp|Proc] The pattern or the block to recognize the engine.
14
+ # @attribute [r] version_matcher
15
+ # @return [Regexp|Proc] The pattern or the block to recognize the version.
16
+ class Browser < Base
17
+ attr_reader :name, :engine_matcher, :version_matcher
18
+
19
+ # Creates a new definition.
20
+ #
21
+ # @param id [Symbol] The platform id.
22
+ # @param name [String] The platform name.
23
+ # @param engine_matcher [Regexp|Proc] The pattern or the block to recognize the engine.
24
+ # @param version_matcher [Regexp|Proc] The pattern or the block to recognize the version.
25
+ def initialize(id, name, engine_matcher, version_matcher, **_)
26
+ @id = id
27
+ @name = name
28
+ @engine_matcher = engine_matcher
29
+ @version_matcher = version_matcher
30
+ end
31
+
32
+ # Matches against an header.
33
+ #
34
+ # @param header [String] The header to match
35
+ # @return [Array|NilClass] An array with the engine and the version if match succeeded, `false` or `nil` otherwise.
36
+ def match(header)
37
+ # First of all, match the engine
38
+ engine = perform_match(@engine_matcher, header) ? @id : nil
39
+
40
+ if engine
41
+ version = extract_version(perform_match(@version_matcher, header))
42
+ platform = extract_platform(header, engine)
43
+ [Brauser::Value.new(engine), Brauser::Value.new(version), Brauser::Value.new(platform)]
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ # :nodoc:
52
+ def perform_match(pattern, subject)
53
+ method = pattern.is_a?(Regexp) ? :match : :call
54
+ pattern.send(method, subject)
55
+ end
56
+
57
+ # :nodoc:
58
+ # @private
59
+ def extract_version(version)
60
+ # Adjust version
61
+ version = "0.0" if version.blank?
62
+ version = version.to_a.last if version.is_a?(::MatchData)
63
+ Versionomy.parse(version)
64
+ rescue
65
+ version
66
+ end
67
+
68
+ # :nodoc:
69
+ def extract_platform(header, engine)
70
+ catch(:result) {
71
+ Brauser::Definitions.platforms.each do |platform, definition|
72
+ throw(:result, platform) if definition.match(header, engine)
73
+ end
74
+
75
+ nil
76
+ }
77
+ end
78
+ end
79
+ end
80
+ end