wurfl_cloud_client 1.0.1

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