brauser 3.3.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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