temporal-rails 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -4,7 +4,7 @@ Rails to use.
4
4
  Documentation and other useful information can be found at
5
5
  https://github.com/jejacks0n/temporal
6
6
 
7
- Copyright (c) 2011 Jeremy Jackson
7
+ Copyright (c) 2012 Jeremy Jackson
8
8
 
9
9
  Permission is hereby granted, free of charge, to any person obtaining
10
10
  a copy of this software and associated documentation files (the
@@ -5,7 +5,7 @@ module Temporal
5
5
  end
6
6
 
7
7
  def set_time_zone
8
- Time.zone = ActiveSupport::TimeZone.new(cookies[:timezone]) || Rails.application.config.time_zone
8
+ Time.zone = cookies[:timezone] ? ActiveSupport::TimeZone.new(cookies[:timezone]) : Rails.application.config.time_zone
9
9
  end
10
10
  end
11
11
  end
@@ -2,7 +2,7 @@ require 'temporal/controller_additions'
2
2
 
3
3
  module Temporal
4
4
  class Engine < ::Rails::Engine
5
- initializer "temporal.controller_additions" do
5
+ initializer "temporal.controller_additions" do
6
6
  ActiveSupport.on_load(:action_controller) do
7
7
  include Temporal::ControllerAdditions
8
8
  end
@@ -1,3 +1,3 @@
1
1
  module Temporal
2
- VERSION = '0.2.1'
2
+ VERSION = '0.2.2'
3
3
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApplicationController, type: :controller do
4
+
5
+ before do
6
+ Rails.application.config.time_zone = 'Central Time (US & Canada)'
7
+ end
8
+
9
+ it "set the timezone to the configured default if the cookie isn't set" do
10
+ get :welcome
11
+ Time.zone.to_s.should =~ /Central Time/
12
+ response.code.should == "200"
13
+ end
14
+
15
+ it "set the timezone based on the cookie" do
16
+ @request.cookies[:timezone] = 'America/Denver'
17
+ get :welcome
18
+ Time.zone.to_s.should =~ /Denver/
19
+ response.code.should == "200"
20
+ end
21
+
22
+ end
@@ -1,6 +1,8 @@
1
1
  require File.expand_path('../boot', __FILE__)
2
2
 
3
- require 'rails/all'
3
+ require 'action_controller/railtie'
4
+ require 'sprockets/railtie'
5
+
4
6
  require 'evergreen/rails'
5
7
 
6
8
  if defined?(Bundler)
@@ -46,13 +48,13 @@ module Dummy
46
48
  # Use SQL instead of Active Record's schema dumper when creating the database.
47
49
  # This is necessary if your schema can't be completely dumped by the schema dumper,
48
50
  # like if you have constraints or database-specific column types
49
- config.active_record.schema_format = :sql
51
+ #config.active_record.schema_format = :sql
50
52
 
51
53
  # Enforce whitelist mode for mass assignment.
52
54
  # This will create an empty whitelist of attributes available for mass-assignment for all models
53
55
  # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
54
56
  # parameters by using an attr_accessible or attr_protected declaration.
55
- config.active_record.whitelist_attributes = true
57
+ #config.active_record.whitelist_attributes = true
56
58
 
57
59
  # Enable the asset pipeline
58
60
  config.assets.enabled = true
@@ -23,11 +23,11 @@ Dummy::Application.configure do
23
23
  config.action_dispatch.best_standards_support = :builtin
24
24
 
25
25
  # Raise exception on mass assignment protection for Active Record models
26
- config.active_record.mass_assignment_sanitizer = :strict
26
+ #config.active_record.mass_assignment_sanitizer = :strict
27
27
 
28
28
  # Log the query plan for queries taking more than this (works
29
29
  # with SQLite, MySQL, and PostgreSQL)
30
- config.active_record.auto_explain_threshold_in_seconds = 0.5
30
+ #config.active_record.auto_explain_threshold_in_seconds = 0.5
31
31
 
32
32
  # Do not compress assets
33
33
  config.assets.compress = false
@@ -27,10 +27,10 @@ Dummy::Application.configure do
27
27
  # Tell Action Mailer not to deliver emails to the real world.
28
28
  # The :test delivery method accumulates sent emails in the
29
29
  # ActionMailer::Base.deliveries array.
30
- config.action_mailer.delivery_method = :test
30
+ #config.action_mailer.delivery_method = :test
31
31
 
32
32
  # Raise exception on mass assignment protection for Active Record models
33
- config.active_record.mass_assignment_sanitizer = :strict
33
+ #config.active_record.mass_assignment_sanitizer = :strict
34
34
 
35
35
  # Print deprecation notices to the stderr
36
36
  config.active_support.deprecation = :stderr
@@ -1,6 +1,6 @@
1
1
  Dummy::Application.routes.draw do
2
2
 
3
- match '/welcome' => 'application#welcome'
3
+ root to: 'application#welcome'
4
4
 
5
5
  # The priority is based upon order of creation:
6
6
  # first created -> highest priority.
@@ -0,0 +1,16 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended to check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(:version => 0) do
15
+
16
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Temporal do
4
+
5
+ it "is a module" do
6
+ Temporal.should be_a(Module)
7
+ end
8
+
9
+ it "has a version" do
10
+ Temporal::VERSION.should be_a(String)
11
+ end
12
+
13
+ it "defines ControllerAdditions" do
14
+ Temporal::ControllerAdditions.should be_a(Module)
15
+ end
16
+
17
+ it "includes ControllerAdditions in ActionController::Base" do
18
+ ActionController::Base.new.methods.should include(:set_time_zone)
19
+ end
20
+
21
+ end
@@ -2,3 +2,75 @@ require '/assets/temporal.js'
2
2
 
3
3
  describe "Temporal", ->
4
4
 
5
+ beforeEach ->
6
+ document.cookie = 'timezone='
7
+ document.cookie = 'timezone_offset='
8
+ @timezoneStub = {name: 'foo', offset: 0} # 0 here ensure the jsonp request isn't made
9
+
10
+ describe "signature", ->
11
+
12
+ it "has a detect and reference method", ->
13
+ expect(Object.keys(Temporal).length).toBe 2
14
+ expect(Object.keys(Temporal)).toEqual ['detect', 'reference']
15
+ expect(typeof(Temporal.detect)).toBe 'function'
16
+ expect(typeof(Temporal.reference)).toBe 'function'
17
+
18
+
19
+ describe ".detect", ->
20
+
21
+ beforeEach ->
22
+ window.Temporal = Temporal.reference() if Temporal.reference
23
+ @spy = spyOn(Temporal.prototype, 'detectLocally').andReturn @timezoneStub
24
+ @callback = ->
25
+
26
+ it "instantiates an instance and passes arguments", ->
27
+ instance = Temporal.detect('username', @callback)
28
+ expect(@spy).toHaveBeenCalled()
29
+ expect(instance.username).toBe 'username'
30
+ expect(instance.callback).toBe @callback
31
+
32
+
33
+ describe "constructor", ->
34
+
35
+ it "calls #detectLocally", ->
36
+ spy = spyOn(Temporal.prototype, 'detectLocally').andReturn @timezoneStub
37
+ new Temporal()
38
+ expect(spy.callCount).toBe 1
39
+
40
+ it "calls #geoLocate if there's a username for the GeoName API", ->
41
+ spyOn(Temporal.prototype, 'detectLocally').andReturn name: 'foo', offset: 1
42
+ spy = spyOn(Temporal.prototype, 'geoLocate')
43
+ new Temporal('username')
44
+ expect(spy.callCount).toBe 1
45
+
46
+ it "doesn't call #geoLocate if there isn't a username", ->
47
+ spyOn(Temporal.prototype, 'detectLocally').andReturn name: 'foo', offset: 1
48
+ spy = spyOn(Temporal.prototype, 'geoLocate')
49
+ new Temporal()
50
+ expect(spy.callCount).toBe 0
51
+
52
+ it "calls #set", ->
53
+ spyOn(Temporal.prototype, 'detectLocally').andReturn @timezoneStub
54
+ spy = spyOn(Temporal.prototype, 'set')
55
+ new Temporal()
56
+ expect(spy.callCount).toBe 1
57
+ expect(spy).toHaveBeenCalledWith name: 'foo', offset: 0
58
+
59
+
60
+ describe "#detectLocally", ->
61
+
62
+ beforeEach ->
63
+ spyOn(Temporal.prototype, 'detect')
64
+ @temporal = new Temporal()
65
+
66
+ it "returns a quickly determined time zone", ->
67
+ spyOn(Temporal.prototype, 'januaryOffset').andReturn -420
68
+ spyOn(Temporal.prototype, 'juneOffset').andReturn -360
69
+ timezone = @temporal.detectLocally()
70
+ expect(timezone).toEqual name: 'America/Denver', offset: -7
71
+
72
+ it "handles other locations than denver", ->
73
+ spyOn(Temporal.prototype, 'januaryOffset').andReturn 120
74
+ spyOn(Temporal.prototype, 'juneOffset').andReturn 120
75
+ timezone = @temporal.detectLocally()
76
+ expect(timezone).toEqual name: 'Africa/Johannesburg', offset: 2
@@ -0,0 +1,39 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+ ENV['RAILS_ROOT'] = File.expand_path('../dummy', __FILE__)
3
+ require File.expand_path('../dummy/config/environment', __FILE__)
4
+
5
+ require 'rspec/rails'
6
+ require 'rspec/autorun'
7
+
8
+ # Requires supporting ruby files with custom matchers and macros, etc,
9
+ # in spec/support/ and its subdirectories.
10
+ Dir[Temporal::Engine.root.join('spec/support/**/*.rb')].each { |f| require f }
11
+
12
+ RSpec.configure do |config|
13
+ # ## Mock Framework
14
+ #
15
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
16
+ #
17
+ # config.mock_with :mocha
18
+ # config.mock_with :flexmock
19
+ # config.mock_with :rr
20
+
21
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
22
+ #config.fixture_path = "#{::Temporal::Engine.root}/spec/fixtures"
23
+
24
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
25
+ # examples within a transaction, remove the following line or assign false
26
+ # instead of true.
27
+ #config.use_transactional_fixtures = true
28
+
29
+ # If true, the base class of anonymous controllers will be inferred
30
+ # automatically. This will be the default behavior in future versions of
31
+ # rspec-rails.
32
+ config.infer_base_class_for_anonymous_controllers = false
33
+
34
+ # Run specs in random order to surface order dependencies. If you find an
35
+ # order dependency and want to debug it, you can fix the order by providing
36
+ # the seed, which is printed after each run.
37
+ # --seed 1234
38
+ config.order = "random"
39
+ end
@@ -1,41 +1,22 @@
1
- class TimeZone
1
+ # Temporal -- use detect() to detect, and reference() if you need a reference
2
+ # to the class so you can use it.
3
+ # -----------------------------------------------------------------------------
4
+ class Temporal
2
5
 
3
- constructor: (keyOrProperties) ->
4
- if typeof(keyOrProperties) == 'string'
5
- zone = TIMEZONES[keyOrProperties]
6
- @[property] = value for own property, value of zone
7
- @resolveAmbiguity()
8
- else
9
- @[property] = value for own property, value of keyOrProperties
10
-
11
- resolveAmbiguity: ->
12
- ambiguous = AMBIGIOUS_ZONES[@name]
13
- return if typeof(ambiguous) is 'undefined'
14
- for key, value of ambiguous
15
- if Temporal.dateIsDst(DST_START_DATES[value])
16
- @name = value
17
- return
6
+ jsonpCallback = "geoSuccessCallback#{parseInt(Math.random() * 10000)}"
18
7
 
8
+ @detect: (username = null, callback = null) =>
9
+ new Temporal(username, callback)
19
10
 
20
- class Temporal
11
+ constructor: (@username = null, @callback = null) ->
12
+ @detect()
21
13
 
22
- @detect: (@username = null, @callback = null) =>
23
- timezone = @quick()
24
- if timezone.offset != @get().offset
25
- navigator.geolocation.getCurrentPosition(@geoSuccess, ->) if @username and navigator.geolocation
14
+ detect: ->
15
+ timezone = @detectLocally()
16
+ @geoLocate() if @username and navigator.geolocation and timezone.offset != @get().offset
26
17
  @set(timezone)
27
18
 
28
- @geoSuccess: (position) =>
29
- window[JSONP_CALLBACK] = @parseGeoResponse
30
- script = document.createElement('script')
31
- script.setAttribute('src', "http://api.geonames.org/timezoneJSON?lat=#{position.coords.latitude}&lng=#{position.coords.longitude}&username=#{@username}&callback=#{JSONP_CALLBACK}")
32
- document.getElementsByTagName('head')[0].appendChild(script)
33
-
34
- @parseGeoResponse: (response) =>
35
- delete(window[JSONP_CALLBACK])
36
- @set(new TimeZone(name: response.timezoneId, offset: response.rawOffset)) if response.timezoneId
37
-
38
- @quick: =>
19
+ detectLocally: ->
39
20
  januaryOffset = @januaryOffset()
40
21
  juneOffset = @juneOffset()
41
22
  key = {offset: januaryOffset, dst: 0, hemisphere: HEMISPHERE_UNKNOWN}
@@ -45,35 +26,76 @@ class Temporal
45
26
  key = {offset: juneOffset, dst: 1, hemisphere: HEMISPHERE_SOUTH}
46
27
  new TimeZone("#{([key.offset, key.dst].join(','))}#{if key.hemisphere is HEMISPHERE_SOUTH then ',s' else ''}")
47
28
 
48
- @set: (timezone) ->
49
- window.timezone = timezone
29
+ geoLocate: ->
30
+ navigator.geolocation.getCurrentPosition(@geoSuccess, ->)
31
+
32
+ geoSuccess: (position) =>
33
+ window[jsonpCallback] = @parseGeoResponse
34
+ script = document.createElement('script')
35
+ script.setAttribute('src', "http://api.geonames.org/timezoneJSON?lat=#{position.coords.latitude}&lng=#{position.coords.longitude}&username=#{@username}&callback=#{jsonpCallback}")
36
+ document.getElementsByTagName('head')[0].appendChild(script)
37
+
38
+ parseGeoResponse: (response) =>
39
+ delete(window[jsonpCallback])
40
+ @set(new TimeZone(name: response.timezoneId, offset: response.rawOffset)) if response.timezoneId
41
+
42
+ set: (@timezone) ->
43
+ window.timezone = @timezone
50
44
  expiration = new Date()
51
45
  expiration.setMonth(expiration.getMonth() + 1)
52
- document.cookie = "timezone=#{timezone.name}; expires=#{expiration.toGMTString()}"
53
- document.cookie = "timezone_offset=#{timezone.offset}; expires=#{expiration.toGMTString()}"
54
- @callback?(timezone)
46
+ document.cookie = "timezone=#{@timezone.name}; expires=#{expiration.toGMTString()}"
47
+ document.cookie = "timezone_offset=#{@timezone.offset}; expires=#{expiration.toGMTString()}"
48
+ @callback?(@timezone)
55
49
 
56
- @get: ->
50
+ get: ->
57
51
  name: @getCookie('timezone')
58
- offset: parseFloat(@getCookie('timezone_offset'))
52
+ offset: parseFloat(@getCookie('timezone_offset')) || 0
59
53
 
60
- @getCookie: (name) ->
54
+ getCookie: (name) ->
61
55
  match = document.cookie.match(new RegExp("(?:^|;)\\s?#{name}=(.*?)(?:;|$)", 'i'))
62
56
  match && unescape(match[1])
63
57
 
64
- @januaryOffset: ->
58
+ januaryOffset: ->
65
59
  @dateOffset(new Date(2011, 0, 1, 0, 0, 0, 0))
66
60
 
67
- @juneOffset: ->
61
+ juneOffset: ->
68
62
  @dateOffset(new Date(2011, 5, 1, 0, 0, 0, 0))
69
63
 
70
- @dateOffset: (date) ->
64
+ dateOffset: (date) ->
71
65
  -date.getTimezoneOffset()
72
66
 
73
- @dateIsDst: (date) ->
67
+
68
+ # Timezone -- contains offset and timezone name
69
+ # -----------------------------------------------------------------------------
70
+ class TimeZone
71
+
72
+ dateIsDst = (date) ->
74
73
  (((if date.getMonth() > 5 then @juneOffset() else @januaryOffset())) - @dateOffset(date)) isnt 0
75
74
 
76
- JSONP_CALLBACK = "geoSuccessCallback#{parseInt(Math.random() * 10000)}"
75
+ resolveAmbiguity = ->
76
+ ambiguous = AMBIGIOUS_ZONES[@name]
77
+ return if typeof(ambiguous) is 'undefined'
78
+ for key, value of ambiguous
79
+ if dateIsDst(DST_START_DATES[value])
80
+ @name = value
81
+ return
82
+
83
+ constructor: (keyOrProperties) ->
84
+ if typeof(keyOrProperties) == 'string'
85
+ zone = TIMEZONES[keyOrProperties]
86
+ @[property] = value for own property, value of zone
87
+ resolveAmbiguity()
88
+ else
89
+ @[property] = value for own property, value of keyOrProperties
90
+
91
+
92
+ # Expose Temporal to the global scope
93
+ # -----------------------------------------------------------------------------
94
+ @Temporal = {detect: Temporal.detect, reference: -> Temporal}
95
+
96
+
97
+ # Data
98
+ # -----------------------------------------------------------------------------
77
99
  HEMISPHERE_SOUTH = 'SOUTH'
78
100
  HEMISPHERE_NORTH = 'NORTH'
79
101
  HEMISPHERE_UNKNOWN = 'N/A'
@@ -191,5 +213,3 @@ TIMEZONES =
191
213
  '765,1,s': {offset: 12.75, name: 'Pacific/Chatham'}
192
214
  '780,0': {offset: 13, name: 'Pacific/Tongatapu'}
193
215
  '840,0': {offset: 14, name: 'Pacific/Kiritimati'}
194
-
195
- @Temporal = {detect: Temporal.detect}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: temporal-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-11 00:00:00.000000000 Z
12
+ date: 2012-10-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -107,6 +107,22 @@ dependencies:
107
107
  - - ! '>='
108
108
  - !ruby/object:Gem::Version
109
109
  version: 1.0.0
110
+ - !ruby/object:Gem::Dependency
111
+ name: rspec-rails
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
110
126
  description: Javascript timezone detection that also sets Time.zone for Rails to use
111
127
  email:
112
128
  - jejacks0n@gmail.com
@@ -122,6 +138,7 @@ files:
122
138
  - lib/temporal-rails.rb
123
139
  - vendor/assets/javascripts/temporal.js.coffee
124
140
  - LICENSE
141
+ - spec/controllers/application_controller_spec.rb
125
142
  - spec/dummy/Rakefile
126
143
  - spec/dummy/app/assets/javascripts/application.js
127
144
  - spec/dummy/app/controllers/application_controller.rb
@@ -142,10 +159,13 @@ files:
142
159
  - spec/dummy/config/initializers/wrap_parameters.rb
143
160
  - spec/dummy/config/locales/en.yml
144
161
  - spec/dummy/config/routes.rb
162
+ - spec/dummy/db/schema.rb
145
163
  - spec/dummy/public/favicon.ico
146
164
  - spec/dummy/script/rails
165
+ - spec/engine/temporal_spec.rb
147
166
  - spec/javascripts/spec_helper.js
148
167
  - spec/javascripts/temporal_spec.js.coffee
168
+ - spec/spec_helper.rb
149
169
  homepage: http://github.com/jejacks0n/temporal
150
170
  licenses:
151
171
  - MIT
@@ -161,7 +181,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
181
  version: '0'
162
182
  segments:
163
183
  - 0
164
- hash: 2430015501946444903
184
+ hash: -492844622740408129
165
185
  required_rubygems_version: !ruby/object:Gem::Requirement
166
186
  none: false
167
187
  requirements:
@@ -170,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
190
  version: '0'
171
191
  segments:
172
192
  - 0
173
- hash: 2430015501946444903
193
+ hash: -492844622740408129
174
194
  requirements: []
175
195
  rubyforge_project:
176
196
  rubygems_version: 1.8.24
@@ -178,6 +198,7 @@ signing_key:
178
198
  specification_version: 3
179
199
  summary: ! 'Temporal: Javascript timezone detection for Rails'
180
200
  test_files:
201
+ - spec/controllers/application_controller_spec.rb
181
202
  - spec/dummy/Rakefile
182
203
  - spec/dummy/app/assets/javascripts/application.js
183
204
  - spec/dummy/app/controllers/application_controller.rb
@@ -198,7 +219,10 @@ test_files:
198
219
  - spec/dummy/config/initializers/wrap_parameters.rb
199
220
  - spec/dummy/config/locales/en.yml
200
221
  - spec/dummy/config/routes.rb
222
+ - spec/dummy/db/schema.rb
201
223
  - spec/dummy/public/favicon.ico
202
224
  - spec/dummy/script/rails
225
+ - spec/engine/temporal_spec.rb
203
226
  - spec/javascripts/spec_helper.js
204
227
  - spec/javascripts/temporal_spec.js.coffee
228
+ - spec/spec_helper.rb