wurfl_cloud_client 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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +40 -0
  5. data/Rakefile +19 -0
  6. data/lib/wurfl_cloud.rb +49 -0
  7. data/lib/wurfl_cloud/cache/cookie.rb +43 -0
  8. data/lib/wurfl_cloud/cache/local_memory.rb +43 -0
  9. data/lib/wurfl_cloud/cache/memcached.rb +64 -0
  10. data/lib/wurfl_cloud/cache/null.rb +41 -0
  11. data/lib/wurfl_cloud/cache/rails.rb +56 -0
  12. data/lib/wurfl_cloud/client.rb +105 -0
  13. data/lib/wurfl_cloud/configuration.rb +88 -0
  14. data/lib/wurfl_cloud/device_capabilities.rb +78 -0
  15. data/lib/wurfl_cloud/environment.rb +48 -0
  16. data/lib/wurfl_cloud/errors.rb +23 -0
  17. data/lib/wurfl_cloud/helper.rb +21 -0
  18. data/lib/wurfl_cloud/rack/cache_manager.rb +54 -0
  19. data/lib/wurfl_cloud/rails.rb +34 -0
  20. data/lib/wurfl_cloud/version.rb +14 -0
  21. data/spec/files/generic.json +1 -0
  22. data/spec/files/generic_filtered.json +1 -0
  23. data/spec/files/lumia.json +1 -0
  24. data/spec/files/lumia_filtered.json +1 -0
  25. data/spec/files/strange_values.json +1 -0
  26. data/spec/spec_helper.rb +27 -0
  27. data/spec/support/rack_helpers.rb +79 -0
  28. data/spec/support/string_extensions.rb +33 -0
  29. data/spec/wurfl_cloud/client_spec.rb +207 -0
  30. data/spec/wurfl_cloud/configuration_spec.rb +118 -0
  31. data/spec/wurfl_cloud/cookie_cache_spec.rb +51 -0
  32. data/spec/wurfl_cloud/device_capabilities_spec.rb +143 -0
  33. data/spec/wurfl_cloud/environment_spec.rb +93 -0
  34. data/spec/wurfl_cloud/helper_spec.rb +35 -0
  35. data/spec/wurfl_cloud/memcached_cache_spec.rb +122 -0
  36. data/spec/wurfl_cloud/null_cache_spec.rb +37 -0
  37. data/spec/wurfl_cloud/rack_cache_manager_spec.rb +76 -0
  38. data/spec/wurfl_cloud/rails_cache_spec.rb +126 -0
  39. data/spec/wurfl_cloud/server_request_spec.rb +45 -0
  40. data/wurfl_cloud_client.gemspec +38 -0
  41. metadata +171 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d04e8db9f6b0603971e674521eab47bbf65eac09
4
+ data.tar.gz: a3ca3e5922319626662c2e11b513c086c0bec125
5
+ SHA512:
6
+ metadata.gz: 98b2cdd9945df9fc89fb7f3bcaf58f7dade7121c7d2f2fb3e7f32facaf9cf1b1954679b786569fcb5000e62115b32e0f6f5061cebb580bc5995c1d44524f394b
7
+ data.tar.gz: 6c704bd2cba72ea4f0d0726ac5b1e2f98c3b3183e005acd80d024bae92bd41dd5c76807b54858eff3375507cde7e04405a85db6f51ba20a9e04e7c3bf3a868a1
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ coverage
5
+ test_api_key.rb
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in wurfl_cloud_client.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,40 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ wurfl_cloud_client (1.0.0)
5
+ json
6
+ rack
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ addressable (2.2.7)
12
+ crack (0.3.1)
13
+ diff-lcs (1.1.3)
14
+ json (1.8.2)
15
+ multi_json (1.1.0)
16
+ rack (1.6.1)
17
+ rspec (2.8.0)
18
+ rspec-core (~> 2.8.0)
19
+ rspec-expectations (~> 2.8.0)
20
+ rspec-mocks (~> 2.8.0)
21
+ rspec-core (2.8.0)
22
+ rspec-expectations (2.8.0)
23
+ diff-lcs (~> 1.1.2)
24
+ rspec-mocks (2.8.0)
25
+ simplecov (0.6.1)
26
+ multi_json (~> 1.0)
27
+ simplecov-html (~> 0.5.3)
28
+ simplecov-html (0.5.3)
29
+ webmock (1.8.0)
30
+ addressable (>= 2.2.7)
31
+ crack (>= 0.1.7)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ rspec
38
+ simplecov
39
+ webmock
40
+ wurfl_cloud_client!
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+
2
+ ## Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'bundler'
13
+
14
+ task 'build' do
15
+ Bundler::GemHelper.new(Dir.pwd, 'wurfl_cloud_client').build_gem
16
+ end
17
+
18
+ # Bundler::GemHelper.install_tasks
19
+
@@ -0,0 +1,49 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'wurfl_cloud/configuration'
13
+ require 'wurfl_cloud/cache/null'
14
+ require 'wurfl_cloud/cache/cookie'
15
+ require 'wurfl_cloud/version'
16
+ require 'wurfl_cloud/client'
17
+ require 'wurfl_cloud/environment'
18
+ require 'wurfl_cloud/device_capabilities'
19
+ require 'wurfl_cloud/errors'
20
+
21
+ module WurflCloud
22
+
23
+ class << self
24
+
25
+ # A configuration object. See WurflCloud::Configuration.
26
+ attr_writer :configuration
27
+
28
+ # Call this method to modify defaults in your initializers.
29
+ #
30
+ # @example
31
+ # WurflCloud.configure do |config|
32
+ # config.api_key = '00000000:xxxxxxxxxxxxxxxxxxxxxxxxxxx'
33
+ # config.host = 'staging.wurflcloud.com'
34
+ # end
35
+ def configure(silent = false)
36
+ yield(configuration)
37
+ end
38
+
39
+ # The configuration object.
40
+ # @see WurflCloud.configure
41
+ def configuration
42
+ @configuration ||= WurflCloud::Configuration.new
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
49
+ require 'wurfl_cloud/rails' if defined?(Rails)
@@ -0,0 +1,43 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ module WurflCloud
13
+ module Cache
14
+ class Cookie
15
+
16
+ def initialize(options, environment)
17
+ @env = environment
18
+ end
19
+
20
+ attr_accessor :mtime
21
+
22
+ def mtime
23
+ nil
24
+ end
25
+
26
+ # Validates the cache
27
+ # it's a no-op in the cookie cache
28
+ def validate(current_mtime)
29
+ end
30
+
31
+ # Should return the value stored for the key, nil if the key is not in cache
32
+ # The Cookie cache always returns the value of the env (no matter what the key)
33
+ def [](key)
34
+ @env['wurfl.cookie.device_cache']
35
+ end
36
+
37
+ # Sets the value in the cache, for the Cookie cache it sets the env
38
+ def []=(key, value)
39
+ @env['wurfl.cookie.device_cache'] = value
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ module WurflCloud
13
+ module Cache
14
+ class LocalMemory
15
+
16
+ def initialize(options=nil, environment=nil)
17
+ @cache = {}
18
+ end
19
+
20
+ attr_accessor :mtime
21
+
22
+ def mtime
23
+ nil
24
+ end
25
+
26
+ # Validates the cache
27
+ # it's a no-op in the local memory cache
28
+ def validate(current_mtime)
29
+ end
30
+
31
+ # Should return the value stored for the key, nil if the key is not in cache
32
+ # The LocalMemory cache stores the values in the local hash
33
+ def [](key)
34
+ @cache[key]
35
+ end
36
+
37
+ # reads the value from the local hash
38
+ def []=(key, value)
39
+ @cache[key] = value
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,64 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'digest/md5'
13
+ module WurflCloud
14
+ module Cache
15
+ class Memcached
16
+
17
+ def initialize(options, environment)
18
+ opts = options.clone
19
+ server = opts.delete(:server)
20
+ @prefix = opts.delete(:prefix)
21
+ opts[:expires_in] ||= 86400
22
+ @memcached = Dalli::Client.new(server, opts)
23
+ end
24
+
25
+ def prefix
26
+ "#{(@prefix.nil? || @prefix=="") ? "": "#{@prefix}:"}"
27
+ end
28
+
29
+ def key_prefix
30
+ "#{prefix}:#{mtime}:"
31
+ end
32
+
33
+ def mtime
34
+ @memcached.get("#{prefix}mtime")
35
+ end
36
+
37
+ def mtime=(new_mtime)
38
+ @memcached.set("#{prefix}mtime", new_mtime)
39
+ end
40
+
41
+ # Validates the cache
42
+ # checks if the cache is still valid with respect to a new mtime received from the server
43
+ # if the new mtime is different from the one cached then it overwrites the current key
44
+ # prefix thus actually invalidationg the cache
45
+ def validate(current_mtime)
46
+ old_mtime = self.mtime
47
+ if !old_mtime || old_mtime!=current_mtime
48
+ self.mtime = current_mtime
49
+ end
50
+ end
51
+
52
+ # Should return the value stored for the key, nil if the key is not in cache
53
+ # The Memcached cache reads from the mamcached server
54
+ def [](key)
55
+ @memcached.get("#{key_prefix}#{Digest::MD5.hexdigest(key)}")
56
+ end
57
+
58
+ # Stores the value for the key in the mamcached server
59
+ def []=(key, value)
60
+ @memcached.set("#{key_prefix}#{Digest::MD5.hexdigest(key)}", value)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,41 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ module WurflCloud
13
+ module Cache
14
+ class Null
15
+
16
+ def initialize(options, environment)
17
+ end
18
+
19
+ attr_accessor :mtime
20
+
21
+ def mtime
22
+ nil
23
+ end
24
+
25
+ # Validates the cache
26
+ # it's a no-op in the null cache
27
+ def validate(current_mtime)
28
+ end
29
+
30
+ # Should return the value stored for the key, nil if the key is not in cache
31
+ # The Null cache always returns nil (nothing is cacheed)
32
+ def [](key)
33
+ nil
34
+ end
35
+
36
+ # It's a no-op for the Null cache
37
+ def []=(key, value)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,56 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'digest/md5'
13
+ module WurflCloud
14
+ module Cache
15
+ class Rails
16
+
17
+ def initialize(options, environment)
18
+ @prefix = options[:prefix]||''
19
+ end
20
+
21
+ def prefix
22
+ "#{(@prefix.nil? || @prefix=="") ? "": "#{@prefix}:"}"
23
+ end
24
+
25
+ def key_prefix
26
+ "#{prefix}:#{mtime}:"
27
+ end
28
+
29
+ def mtime
30
+ ::Rails.cache.read("#{prefix}mtime")
31
+ end
32
+
33
+ def mtime=(new_mtime)
34
+ ::Rails.cache.write("#{prefix}mtime", new_mtime)
35
+ end
36
+
37
+ # Validates the cache
38
+ # checks if the cache is still valid with respect to a new mtime received from the server
39
+ # if the new mtime is different from the one cached then it overwrites the current key
40
+ # prefix thus actually invalidationg the cache
41
+ def validate(current_mtime)
42
+ end
43
+
44
+ # Should return the value stored for the key, nil if the key is not in cache
45
+ # The Rails cache reads from the Rails.cache object
46
+ def [](key)
47
+ ::Rails.cache.read("#{key_prefix}#{Digest::MD5.hexdigest(key)}")
48
+ end
49
+
50
+ # Stores the value for the key in the Rails.cache
51
+ def []=(key, value)
52
+ ::Rails.cache.write("#{key_prefix}#{Digest::MD5.hexdigest(key)}", value)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,105 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'wurfl_cloud/device_capabilities'
13
+ require 'net/http'
14
+
15
+ module WurflCloud
16
+ class Client
17
+
18
+ attr_reader :device_capabilities, :read_from_cache
19
+
20
+ def initialize(e, c)
21
+ @environment = e
22
+ @cache = c
23
+ @device_capabilities = WurflCloud::DeviceCapabilities.new(@environment.user_agent)
24
+ @read_from_cache = false
25
+ end
26
+
27
+ def [](capability_key)
28
+ if !@device_capabilities.has_key?(capability_key) && @read_from_cache
29
+ load_from_server!
30
+ store_in_cache
31
+ end
32
+ @device_capabilities[capability_key]
33
+ end
34
+
35
+ def detect
36
+ unless load_from_cache
37
+ load_from_server!
38
+ store_in_cache
39
+ end
40
+ end
41
+
42
+ def load_from_server!
43
+ begin
44
+ # make the request
45
+ Net::HTTP.start(WurflCloud.configuration.host,WurflCloud.configuration.port) do |http|
46
+ req = Net::HTTP::Get.new(WurflCloud.configuration.path, http_headers)
47
+ req.basic_auth WurflCloud.configuration.api_user, WurflCloud.configuration.api_password
48
+ res = http.request(req)
49
+
50
+ # emit the result
51
+ if res.code=="200"
52
+ # read the response
53
+ @device_capabilities = WurflCloud::DeviceCapabilities.parse(res.body)
54
+ @cache.validate(@device_capabilities.mtime.to_i)
55
+ @read_from_cache = false
56
+ else
57
+ raise WurflCloud::Errors::ConnectionError.new("#{res.code} #{res.message}")
58
+ end
59
+ end
60
+ rescue WurflCloud::Errors::GenericError => exc
61
+ raise exc
62
+ rescue Exception => exc
63
+ raise WurflCloud::Errors::ConnectionError.new(exc.message)
64
+ end
65
+ end
66
+
67
+ class << self
68
+
69
+ def detect_device(environment, cache)
70
+ new(environment, cache).tap do |client|
71
+ client.detect
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ private
78
+
79
+ def http_headers
80
+ {
81
+ 'X-Cloud-Client' => "WurflCloudClient/Ruby_#{WurflCloud::VERSION}",
82
+ "Content-Type"=>"application/json; charset=UTF-8"
83
+ }.tap do |h|
84
+ h['User-Agent'] = @environment.user_agent unless @environment.user_agent.nil?
85
+ h['X-Forwarded-For'] = @environment.x_forwarded_for unless @environment.x_forwarded_for.nil?
86
+ h['X-Accept'] = @environment.x_accept unless @environment.x_accept.nil?
87
+ h['X-Wap-Profile'] = @environment.x_wap_profile unless @environment.x_wap_profile.nil?
88
+ end
89
+ end
90
+
91
+ def store_in_cache
92
+ @cache[@environment.user_agent] = @device_capabilities.to_hash
93
+ end
94
+
95
+ def load_from_cache
96
+ if cached_capabilities = @cache[@environment.user_agent]
97
+ @device_capabilities = WurflCloud::DeviceCapabilities.new(@environment.user_agent)
98
+ @device_capabilities.merge(cached_capabilities)
99
+ @read_from_cache = true
100
+ return true
101
+ end
102
+ end
103
+
104
+ end
105
+ end