volt 0.9.6 → 0.9.7.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/CHANGELOG.md +26 -0
- data/Gemfile +6 -1
- data/README.md +2 -0
- data/Rakefile +1 -0
- data/app/volt/models/active_volt_instance.rb +8 -6
- data/app/volt/models/user.rb +11 -2
- data/app/volt/models/volt_app_property.rb +8 -0
- data/app/volt/tasks/query_tasks.rb +23 -31
- data/app/volt/tasks/store_tasks.rb +2 -2
- data/app/volt/tasks/volt_admin_tasks.rb +24 -0
- data/docs/UPGRADE_GUIDE.md +6 -0
- data/lib/volt.rb +19 -12
- data/lib/volt/boot.rb +1 -0
- data/lib/volt/cli.rb +19 -8
- data/lib/volt/cli/console.rb +0 -1
- data/lib/volt/cli/generators.rb +14 -3
- data/lib/volt/cli/migrate.rb +26 -0
- data/lib/volt/config.rb +17 -4
- data/lib/volt/controllers/http_controller.rb +12 -0
- data/lib/volt/data_stores/base_adaptor_client.rb +2 -2
- data/lib/volt/data_stores/base_adaptor_server.rb +2 -0
- data/lib/volt/data_stores/data_store.rb +20 -14
- data/lib/volt/extra_core/class.rb +28 -14
- data/lib/volt/extra_core/hash.rb +5 -0
- data/lib/volt/extra_core/string.rb +3 -1
- data/lib/volt/helpers/time.rb +9 -43
- data/lib/volt/helpers/time/calculations.rb +204 -0
- data/lib/volt/helpers/time/distance.rb +63 -0
- data/lib/volt/helpers/time/duration.rb +71 -0
- data/lib/volt/helpers/time/local_calculations.rb +49 -0
- data/lib/volt/helpers/time/local_volt_time.rb +23 -0
- data/lib/volt/helpers/time/numeric.rb +59 -0
- data/lib/volt/helpers/time/volt_time.rb +170 -0
- data/lib/volt/models.rb +5 -0
- data/lib/volt/models/array_model.rb +33 -6
- data/lib/volt/models/associations.rb +146 -23
- data/lib/volt/models/buffer.rb +38 -41
- data/lib/volt/models/cursor.rb +15 -0
- data/lib/volt/models/errors.rb +11 -0
- data/lib/volt/models/field_helpers.rb +108 -68
- data/lib/volt/models/helpers/array_model.rb +4 -0
- data/lib/volt/models/helpers/base.rb +8 -1
- data/lib/volt/models/helpers/change_helpers.rb +31 -12
- data/lib/volt/models/helpers/defaults.rb +15 -0
- data/lib/volt/models/location.rb +20 -6
- data/lib/volt/models/migrations/migration.rb +23 -0
- data/lib/volt/models/migrations/migration_runner.rb +146 -0
- data/lib/volt/models/model.rb +38 -1
- data/lib/volt/models/permissions.rb +8 -1
- data/lib/volt/models/persistors/array_store.rb +87 -8
- data/lib/volt/models/persistors/base.rb +19 -0
- data/lib/volt/models/persistors/model_store.rb +1 -1
- data/lib/volt/models/persistors/page.rb +4 -1
- data/lib/volt/models/persistors/query/query_identifier.rb +102 -0
- data/lib/volt/models/persistors/query/query_listener.rb +57 -12
- data/lib/volt/models/root_models/root_models.rb +19 -0
- data/lib/volt/models/url.rb +11 -2
- data/lib/volt/models/validations/validations.rb +5 -2
- data/lib/volt/models/validators/type_validator.rb +11 -0
- data/lib/volt/models/validators/unique_validator.rb +2 -2
- data/lib/volt/page/bindings/attribute_binding.rb +23 -1
- data/lib/volt/page/targets/attribute_section.rb +7 -0
- data/lib/volt/page/targets/binding_document/component_node.rb +44 -18
- data/lib/volt/page/targets/binding_document/tag_node.rb +41 -0
- data/lib/volt/page/tasks.rb +16 -8
- data/lib/volt/queries/live_query.rb +109 -0
- data/lib/volt/queries/live_query_pool.rb +58 -0
- data/lib/volt/queries/live_subquery.rb +0 -0
- data/lib/volt/queries/query_association_splitter.rb +31 -0
- data/lib/volt/queries/query_diff.rb +100 -0
- data/lib/volt/queries/query_runner.rb +110 -0
- data/lib/volt/queries/query_subscription.rb +80 -0
- data/lib/volt/queries/query_subscription_pool.rb +37 -0
- data/lib/volt/reactive/eventable.rb +8 -0
- data/lib/volt/reactive/reactive_array.rb +0 -4
- data/lib/volt/router/routes.rb +81 -31
- data/lib/volt/server/message_bus/base_message_bus.rb +9 -3
- data/lib/volt/server/message_bus/peer_to_peer.rb +6 -6
- data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +1 -1
- data/lib/volt/server/middleware/default_middleware_stack.rb +12 -8
- data/lib/volt/server/rack/component_paths.rb +31 -4
- data/lib/volt/server/rack/http_content_types.rb +62 -0
- data/lib/volt/server/rack/http_resource.rb +1 -1
- data/lib/volt/server/rack/index_files.rb +8 -1
- data/lib/volt/server/rack/opal_files.rb +16 -1
- data/lib/volt/server/rack/sprockets_helpers_setup.rb +32 -1
- data/lib/volt/server/socket_connection_handler.rb +16 -7
- data/lib/volt/server/template_handlers/sprockets_component_handler.rb +5 -3
- data/lib/volt/spec/capybara.rb +4 -3
- data/lib/volt/spec/setup.rb +5 -0
- data/lib/volt/tasks/dispatcher.rb +3 -1
- data/lib/volt/utils/data_transformer.rb +4 -4
- data/lib/volt/utils/ejson.rb +19 -6
- data/lib/volt/utils/promise_extensions.rb +1 -1
- data/lib/volt/utils/time_opal_patch.rb +749 -0
- data/lib/volt/utils/time_patch.rb +11 -4
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +19 -11
- data/lib/volt/volt/properties.rb +24 -0
- data/lib/volt/volt/server_setup/app.rb +30 -7
- data/lib/volt/volt/users.rb +15 -3
- data/spec/apps/kitchen_sink/Gemfile +5 -1
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
- data/spec/apps/kitchen_sink/app/main/controllers/save_controller.rb +1 -1
- data/spec/apps/kitchen_sink/app/main/controllers/server/simple_http_controller.rb +4 -0
- data/spec/apps/kitchen_sink/app/main/controllers/todos_controller.rb +4 -2
- data/spec/apps/kitchen_sink/app/main/models/post.rb +0 -1
- data/spec/apps/kitchen_sink/app/main/models/todo.rb +4 -0
- data/spec/apps/kitchen_sink/app/main/views/mailers/reset_password.html +10 -0
- data/spec/apps/kitchen_sink/app/main/views/todos/index.html +2 -0
- data/spec/apps/kitchen_sink/config/app.rb +2 -0
- data/spec/apps/migrations/config/db/migrations/1445111704_migration1.rb +7 -0
- data/spec/apps/migrations/config/db/migrations/1445113517_migration2.rb +7 -0
- data/spec/apps/migrations/config/db/migrations/1445115200_migration3.rb +7 -0
- data/spec/extra_core/class_spec.rb +10 -0
- data/spec/helpers/distance_spec.rb +35 -0
- data/spec/helpers/duration_spec.rb +160 -0
- data/spec/helpers/volt_time_spec.rb +275 -0
- data/spec/integration/callbacks_spec.rb +2 -1
- data/spec/integration/http_endpoints_spec.rb +4 -0
- data/spec/integration/save_spec.rb +1 -1
- data/spec/integration/todos_spec.rb +7 -5
- data/spec/models/array_model_spec.rb +17 -3
- data/spec/models/associations_spec.rb +48 -1
- data/spec/models/field_helpers_spec.rb +7 -3
- data/spec/models/migrations/migration_runner_spec.rb +69 -0
- data/spec/models/model_spec.rb +42 -8
- data/spec/models/permissions_spec.rb +20 -8
- data/spec/models/persistors/array_store_spec.rb +18 -0
- data/spec/models/persistors/page_spec.rb +15 -10
- data/spec/models/persistors/store_spec.rb +13 -3
- data/spec/models/url_spec.rb +4 -3
- data/spec/models/user_spec.rb +6 -3
- data/spec/models/user_validation_spec.rb +3 -3
- data/spec/models/validations_spec.rb +4 -0
- data/spec/models/validators/block_validations_spec.rb +9 -5
- data/spec/models/validators/email_validator_spec.rb +2 -0
- data/spec/models/validators/lifecycle_callbacks_spec.rb +86 -0
- data/spec/models/validators/unique_validator_spec.rb +1 -0
- data/spec/page/path_string_renderer_spec.rb +5 -0
- data/spec/queries/live_query_spec.rb +16 -0
- data/spec/queries/query_association_splitter_spec.rb +14 -0
- data/spec/queries/query_diff_spec.rb +132 -0
- data/spec/queries/query_identifier_spec.rb +98 -0
- data/spec/queries/query_runner_spec.rb +63 -0
- data/spec/queries/query_tracker_spec.rb +141 -0
- data/spec/router/routes_spec.rb +52 -21
- data/spec/server/middleware/rack_content_types_spec.rb +78 -0
- data/spec/server/rack/asset_files_spec.rb +38 -30
- data/spec/spec_helper.rb +8 -0
- data/spec/utils/ejson_spec.rb +9 -8
- data/spec/utils/ejson_volt_time_spec.rb +65 -0
- data/templates/migration/migration.rb.tt +9 -0
- data/templates/newgem/gitignore.tt +1 -0
- data/templates/project/Gemfile.tt +19 -2
- data/templates/project/README.md.tt +6 -1
- data/templates/project/app/main/config/dependencies.rb +6 -0
- data/templates/project/config/app.rb.tt +18 -4
- data/volt.gemspec +2 -2
- metadata +73 -16
- data/app/volt/tasks/live_query/live_query_pool.rb +0 -48
- data/app/volt/tasks/live_query/query_tracker.rb +0 -92
- data/spec/tasks/live_query_spec.rb +0 -18
- data/spec/tasks/query_tasks.rb +0 -7
- data/spec/tasks/query_tracker_spec.rb +0 -145
@@ -30,7 +30,14 @@ module Volt
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def html
|
33
|
-
|
33
|
+
# Check for a precompiled
|
34
|
+
index_path = File.expand_path(File.join(Volt.root, 'public/index.html'))
|
35
|
+
|
36
|
+
# Next check for one in config/base
|
37
|
+
unless File.exists?(index_path)
|
38
|
+
index_path = File.expand_path(File.join(Volt.root, 'config/base/index.html'))
|
39
|
+
end
|
40
|
+
|
34
41
|
html = File.read(index_path)
|
35
42
|
|
36
43
|
ERB.new(html, nil, '-').result(binding)
|
@@ -82,7 +82,22 @@ module Volt
|
|
82
82
|
environment = @environment
|
83
83
|
|
84
84
|
builder.map(app_url) do
|
85
|
-
|
85
|
+
# This map block takes over all serving for /app, so here we serve out
|
86
|
+
# of public/app if the file isn't found in sprockets.
|
87
|
+
# TODO: We should really let Rack::Cascade run from the default
|
88
|
+
# middleware stack.
|
89
|
+
not_found = lambda { |env| [404, {}, []] }
|
90
|
+
opts = {
|
91
|
+
urls: [''],
|
92
|
+
root: ['public/app'],
|
93
|
+
header_rules: [
|
94
|
+
[:all, { 'Cache-Control' => 'public, max-age=86400' }]
|
95
|
+
]
|
96
|
+
}
|
97
|
+
static = Rack::Static.new(not_found, opts)
|
98
|
+
|
99
|
+
run Rack::Cascade.new([environment, static])
|
100
|
+
# run environment
|
86
101
|
end
|
87
102
|
|
88
103
|
# Remove dup paths
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'sprockets'
|
1
2
|
require 'sprockets-helpers'
|
2
3
|
|
3
4
|
module Volt
|
@@ -38,6 +39,7 @@ module Volt
|
|
38
39
|
# We "freedom-patch" sprockets-helpers asset_path method to
|
39
40
|
# automatically link assets.
|
40
41
|
define_method(:asset_path) do |source, options = {}|
|
42
|
+
# puts "AP: #{source.inspect}"
|
41
43
|
relative_path = source =~ /^[.][.]\//
|
42
44
|
if relative_path
|
43
45
|
component_root = logical_path.gsub(/\/[^\/]+$/, '')
|
@@ -103,4 +105,33 @@ module Volt
|
|
103
105
|
output.join('/')
|
104
106
|
end
|
105
107
|
end
|
106
|
-
end
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# module Sprockets
|
112
|
+
# class Context
|
113
|
+
# # We have to reinclude this because of some ```require``` thread saftey issues.
|
114
|
+
# def find_asset_path(uri, source, options = {})
|
115
|
+
# if Helpers.manifest && options[:manifest] != false
|
116
|
+
# manifest_path = Helpers.manifest.assets[uri.path]
|
117
|
+
# return Helpers::ManifestPath.new(uri, manifest_path, options) if manifest_path
|
118
|
+
# end
|
119
|
+
|
120
|
+
# if Sprockets::Helpers.are_using_sprockets_3
|
121
|
+
# resolved = assets_environment.resolve(uri.path)
|
122
|
+
|
123
|
+
# if resolved
|
124
|
+
# return Helpers::AssetPath.new(uri, assets_environment[uri.path], options)
|
125
|
+
# else
|
126
|
+
# return Helpers::FilePath.new(uri, options)
|
127
|
+
# end
|
128
|
+
# else
|
129
|
+
# assets_environment.resolve(uri.path) do |path|
|
130
|
+
# return Helpers::AssetPath.new(uri, assets_environment[path], options)
|
131
|
+
# end
|
132
|
+
|
133
|
+
# return Helpers::FilePath.new(uri, options)
|
134
|
+
# end
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
# end
|
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'volt/utils/ejson'
|
2
2
|
require File.join(File.dirname(__FILE__), '../../../app/volt/tasks/query_tasks')
|
3
3
|
|
4
|
+
# SocketConnectionHandler is often referred to as "channel" when on the server
|
5
|
+
# side.
|
6
|
+
#
|
7
|
+
# NOTE: On the forking server, the "channel" is actually a DRb reference back
|
8
|
+
# to the main process. So we should try to put as few objects as possible
|
9
|
+
# in here.
|
4
10
|
module Volt
|
5
11
|
class SocketConnectionHandler
|
6
12
|
# Create one instance of the dispatcher
|
@@ -13,11 +19,14 @@ module Volt
|
|
13
19
|
def initialize(session, *args)
|
14
20
|
@session = session
|
15
21
|
|
16
|
-
|
17
|
-
@@
|
22
|
+
# Keep a list of all channels
|
23
|
+
@@all_channels ||= []
|
24
|
+
@@all_channels << self
|
18
25
|
|
19
26
|
# Trigger a client connect event
|
20
|
-
@@dispatcher.volt_app
|
27
|
+
if @@dispatcher.respond_to?(:volt_app)
|
28
|
+
@@dispatcher.volt_app.trigger!("client_connect")
|
29
|
+
end
|
21
30
|
|
22
31
|
end
|
23
32
|
|
@@ -49,13 +58,13 @@ module Volt
|
|
49
58
|
end
|
50
59
|
|
51
60
|
def self.channels
|
52
|
-
@@
|
61
|
+
@@all_channels
|
53
62
|
end
|
54
63
|
|
55
64
|
# Sends a message to all, optionally skipping a users channel
|
56
65
|
def self.send_message_all(skip_channel = nil, *args)
|
57
|
-
return unless defined?(@@
|
58
|
-
@@
|
66
|
+
return unless defined?(@@all_channels)
|
67
|
+
@@all_channels.each do |channel|
|
59
68
|
next if skip_channel && channel == skip_channel
|
60
69
|
channel.send_message(*args)
|
61
70
|
end
|
@@ -108,7 +117,7 @@ module Volt
|
|
108
117
|
unless @closed
|
109
118
|
@closed = true
|
110
119
|
# Remove ourself from the available channels
|
111
|
-
@@
|
120
|
+
@@all_channels.delete(self)
|
112
121
|
|
113
122
|
begin
|
114
123
|
@@dispatcher.close_channel(self)
|
@@ -54,10 +54,12 @@ module Sprockets
|
|
54
54
|
data = env.read_file(input[:filename], input[:content_type])
|
55
55
|
end
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
dependencies = Set.new(input[:metadata][:dependencies])
|
58
|
+
dependencies += [env.build_file_digest_uri(input[:filename])]
|
59
59
|
|
60
|
-
|
60
|
+
# For some reason this version doesn't work, even though its used
|
61
|
+
# elsewhere in sprockets
|
62
|
+
# dependencies = input[:metadata][:dependencies]
|
61
63
|
# dependencies.merge(env.build_file_digest_uri(input[:filename]))
|
62
64
|
|
63
65
|
{ data: data, dependencies: dependencies }
|
data/lib/volt/spec/capybara.rb
CHANGED
@@ -35,6 +35,10 @@ module Volt
|
|
35
35
|
require 'selenium-webdriver'
|
36
36
|
require 'volt/server'
|
37
37
|
|
38
|
+
|
39
|
+
# Setup server, use existing booted app
|
40
|
+
Capybara.app = Server.new(app_path, volt_app).app
|
41
|
+
|
38
42
|
case RUNNING_SERVER
|
39
43
|
when 'thin'
|
40
44
|
Capybara.server do |app, port|
|
@@ -48,9 +52,6 @@ module Volt
|
|
48
52
|
end.run.join
|
49
53
|
end
|
50
54
|
end
|
51
|
-
|
52
|
-
# Setup server, use existing booted app
|
53
|
-
Capybara.app = Server.new(app_path, volt_app).app
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
data/lib/volt/spec/setup.rb
CHANGED
@@ -56,6 +56,7 @@ module Volt
|
|
56
56
|
@__store_accessed = true
|
57
57
|
volt_app.store
|
58
58
|
end
|
59
|
+
let(:cleanup_db) { @__store_accessed = true }
|
59
60
|
let(:volt_app) { volt_app }
|
60
61
|
let(:params) { volt_app.params }
|
61
62
|
|
@@ -65,6 +66,10 @@ module Volt
|
|
65
66
|
if url.instance_variable_get('@params')
|
66
67
|
url.instance_variable_set('@params', nil)
|
67
68
|
end
|
69
|
+
|
70
|
+
# Reset volt_app
|
71
|
+
$volt_app = volt_app
|
72
|
+
Thread.current['volt_app'] = volt_app
|
68
73
|
end
|
69
74
|
|
70
75
|
if RUBY_PLATFORM != 'opal'
|
@@ -7,6 +7,8 @@ require 'timeout'
|
|
7
7
|
module Volt
|
8
8
|
# The task dispatcher is responsible for taking incoming messages
|
9
9
|
# from the socket channel and dispatching them to the proper handler.
|
10
|
+
#
|
11
|
+
# On the forking server, this runs in the child.
|
10
12
|
class Dispatcher
|
11
13
|
# When we pass the dispatcher over DRb, don't send a copy, just proxy.
|
12
14
|
include DRb::DRbUndumped
|
@@ -51,7 +53,7 @@ module Volt
|
|
51
53
|
# server, returning the result to the client.
|
52
54
|
# Tasks returning a promise will wait to return.
|
53
55
|
def dispatch(channel, message)
|
54
|
-
# Dispatch the task in the worker pool.
|
56
|
+
# Dispatch the task in the worker pool. Pass in the meta data
|
55
57
|
@worker_pool.post do
|
56
58
|
begin
|
57
59
|
dispatch_in_thread(channel, message)
|
@@ -9,16 +9,16 @@ module Volt
|
|
9
9
|
# the block the value. The return value from the block replaces the
|
10
10
|
# previous value.
|
11
11
|
# NOTE: This does not yield hashes or arrays.
|
12
|
-
def self.transform(data, &block)
|
12
|
+
def self.transform(data, transform_keys=true, &block)
|
13
13
|
if data.is_a?(Hash)
|
14
14
|
data.map do |key, value|
|
15
|
-
key = transform(key, &block)
|
16
|
-
value = transform(value, &block)
|
15
|
+
key = transform(key, transform_keys, &block) if transform_keys
|
16
|
+
value = transform(value, transform_keys, &block)
|
17
17
|
[key, value]
|
18
18
|
end.to_h
|
19
19
|
elsif data.is_a?(Array)
|
20
20
|
data.map do |value|
|
21
|
-
transform(value, &block)
|
21
|
+
transform(value, transform_keys, &block)
|
22
22
|
end
|
23
23
|
else
|
24
24
|
# yield to the trasnformer
|
data/lib/volt/utils/ejson.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
require 'json'
|
2
2
|
|
3
|
+
# We auto require time on the server, so we can decode VoltTime's in the parent
|
4
|
+
# process on the ForkingServer. (Since no user code is booted in the forking
|
5
|
+
# server). On the client the user has to require it if they want to use it.
|
6
|
+
unless RUBY_PLATFORM == 'opal'
|
7
|
+
require 'volt/helpers/time'
|
8
|
+
end
|
9
|
+
|
3
10
|
module Volt
|
4
11
|
class EJSON
|
5
12
|
class NonEjsonType < Exception ; end
|
@@ -24,9 +31,15 @@ module Volt
|
|
24
31
|
return escape.map do |key, value|
|
25
32
|
[key, decode(value)]
|
26
33
|
end.to_h
|
27
|
-
elsif obj.size == 1
|
28
|
-
if time
|
29
|
-
|
34
|
+
elsif obj.size == 1
|
35
|
+
if (time = obj['$date'])
|
36
|
+
if defined?(VoltTime)
|
37
|
+
if time.is_a?(Numeric)
|
38
|
+
return VoltTime.at(time / 1000.0)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
raise "VoltTime is not defined, be sure to require 'volt/helpers/time'."
|
42
|
+
end
|
30
43
|
end
|
31
44
|
end
|
32
45
|
|
@@ -44,15 +57,15 @@ module Volt
|
|
44
57
|
elsif Hash === obj
|
45
58
|
obj.map do |key, value|
|
46
59
|
if key == '$date'
|
60
|
+
value = {key => encode(value)}
|
47
61
|
key = '$escape'
|
48
|
-
value = {'$date' => encode(value)}
|
49
62
|
else
|
50
63
|
value = encode(value)
|
51
64
|
end
|
52
65
|
|
53
66
|
[key, value]
|
54
67
|
end.to_h
|
55
|
-
elsif
|
68
|
+
elsif (defined?(VoltTime) && VoltTime === obj)
|
56
69
|
{'$date' => obj.to_i * 1_000}
|
57
70
|
elsif OTHER_VALID_CLASSES.any? {|klass| obj.is_a?(klass) }
|
58
71
|
obj
|
@@ -62,4 +75,4 @@ module Volt
|
|
62
75
|
end
|
63
76
|
end
|
64
77
|
end
|
65
|
-
end
|
78
|
+
end
|
@@ -0,0 +1,749 @@
|
|
1
|
+
# Copied from https://github.com/opal/opal/blob/dd81fb4bfe337c0321ef1a8f7def2a3049a3fd83/opal/corelib/time.rb
|
2
|
+
# This patches time to the level in Opal 0.9.0 so that Volt can continue to run against Opal 0.8.0 and
|
3
|
+
# implement VoltTime
|
4
|
+
|
5
|
+
require 'corelib/comparable'
|
6
|
+
|
7
|
+
class Time
|
8
|
+
include Comparable
|
9
|
+
|
10
|
+
%x{
|
11
|
+
var days_of_week = #{%w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday]},
|
12
|
+
short_days = #{%w[Sun Mon Tue Wed Thu Fri Sat]},
|
13
|
+
short_months = #{%w[Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec]},
|
14
|
+
long_months = #{%w[January February March April May June July August September October November December]};
|
15
|
+
}
|
16
|
+
|
17
|
+
def self.at(seconds, frac = undefined)
|
18
|
+
%x{
|
19
|
+
var result;
|
20
|
+
|
21
|
+
if (#{Time === seconds}) {
|
22
|
+
if (frac !== undefined) {
|
23
|
+
#{raise TypeError, "can't convert Time into an exact number"}
|
24
|
+
}
|
25
|
+
result = new Date(seconds.getTime());
|
26
|
+
result.is_utc = seconds.is_utc;
|
27
|
+
return result;
|
28
|
+
}
|
29
|
+
|
30
|
+
if (!seconds.$$is_number) {
|
31
|
+
seconds = #{Opal.coerce_to!(seconds, Integer, :to_int)};
|
32
|
+
}
|
33
|
+
|
34
|
+
if (frac === undefined) {
|
35
|
+
return new Date(seconds * 1000);
|
36
|
+
}
|
37
|
+
|
38
|
+
if (!frac.$$is_number) {
|
39
|
+
frac = #{Opal.coerce_to!(frac, Integer, :to_int)};
|
40
|
+
}
|
41
|
+
|
42
|
+
return new Date(seconds * 1000 + (frac / 1000));
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
%x{
|
47
|
+
function time_params(year, month, day, hour, min, sec) {
|
48
|
+
if (year.$$is_string) {
|
49
|
+
year = parseInt(year, 10);
|
50
|
+
} else {
|
51
|
+
year = #{Opal.coerce_to!(`year`, Integer, :to_int)};
|
52
|
+
}
|
53
|
+
|
54
|
+
if (month === nil) {
|
55
|
+
month = 1;
|
56
|
+
} else if (!month.$$is_number) {
|
57
|
+
if (#{`month`.respond_to?(:to_str)}) {
|
58
|
+
month = #{`month`.to_str};
|
59
|
+
switch (month.toLowerCase()) {
|
60
|
+
case 'jan': month = 1; break;
|
61
|
+
case 'feb': month = 2; break;
|
62
|
+
case 'mar': month = 3; break;
|
63
|
+
case 'apr': month = 4; break;
|
64
|
+
case 'may': month = 5; break;
|
65
|
+
case 'jun': month = 6; break;
|
66
|
+
case 'jul': month = 7; break;
|
67
|
+
case 'aug': month = 8; break;
|
68
|
+
case 'sep': month = 9; break;
|
69
|
+
case 'oct': month = 10; break;
|
70
|
+
case 'nov': month = 11; break;
|
71
|
+
case 'dec': month = 12; break;
|
72
|
+
default: month = #{`month`.to_i};
|
73
|
+
}
|
74
|
+
} else {
|
75
|
+
month = #{Opal.coerce_to!(`month`, Integer, :to_int)};
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
if (month < 1 || month > 12) {
|
80
|
+
#{raise ArgumentError, "month out of range: #{`month`}"}
|
81
|
+
}
|
82
|
+
month = month - 1;
|
83
|
+
|
84
|
+
if (day === nil) {
|
85
|
+
day = 1;
|
86
|
+
} else if (day.$$is_string) {
|
87
|
+
day = parseInt(day, 10);
|
88
|
+
} else {
|
89
|
+
day = #{Opal.coerce_to!(`day`, Integer, :to_int)};
|
90
|
+
}
|
91
|
+
|
92
|
+
if (day < 1 || day > 31) {
|
93
|
+
#{raise ArgumentError, "day out of range: #{`day`}"}
|
94
|
+
}
|
95
|
+
|
96
|
+
if (hour === nil) {
|
97
|
+
hour = 0;
|
98
|
+
} else if (hour.$$is_string) {
|
99
|
+
hour = parseInt(hour, 10);
|
100
|
+
} else {
|
101
|
+
hour = #{Opal.coerce_to!(`hour`, Integer, :to_int)};
|
102
|
+
}
|
103
|
+
|
104
|
+
if (hour < 0 || hour > 24) {
|
105
|
+
#{raise ArgumentError, "hour out of range: #{`hour`}"}
|
106
|
+
}
|
107
|
+
|
108
|
+
if (min === nil) {
|
109
|
+
min = 0;
|
110
|
+
} else if (min.$$is_string) {
|
111
|
+
min = parseInt(min, 10);
|
112
|
+
} else {
|
113
|
+
min = #{Opal.coerce_to!(`min`, Integer, :to_int)};
|
114
|
+
}
|
115
|
+
|
116
|
+
if (min < 0 || min > 59) {
|
117
|
+
#{raise ArgumentError, "min out of range: #{`min`}"}
|
118
|
+
}
|
119
|
+
|
120
|
+
if (sec === nil) {
|
121
|
+
sec = 0;
|
122
|
+
} else if (!sec.$$is_number) {
|
123
|
+
if (sec.$$is_string) {
|
124
|
+
sec = parseInt(sec, 10);
|
125
|
+
} else {
|
126
|
+
sec = #{Opal.coerce_to!(`sec`, Integer, :to_int)};
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
if (sec < 0 || sec > 60) {
|
131
|
+
#{raise ArgumentError, "sec out of range: #{`sec`}"}
|
132
|
+
}
|
133
|
+
|
134
|
+
return [year, month, day, hour, min, sec];
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
def self.new(year = undefined, month = nil, day = nil, hour = nil, min = nil, sec = nil, utc_offset = nil)
|
139
|
+
%x{
|
140
|
+
var args, result;
|
141
|
+
|
142
|
+
if (year === undefined) {
|
143
|
+
return new Date();
|
144
|
+
}
|
145
|
+
|
146
|
+
if (utc_offset !== nil) {
|
147
|
+
#{raise ArgumentError, 'Opal does not support explicitly specifying UTC offset for Time'}
|
148
|
+
}
|
149
|
+
|
150
|
+
args = time_params(year, month, day, hour, min, sec);
|
151
|
+
year = args[0];
|
152
|
+
month = args[1];
|
153
|
+
day = args[2];
|
154
|
+
hour = args[3];
|
155
|
+
min = args[4];
|
156
|
+
sec = args[5];
|
157
|
+
|
158
|
+
result = new Date(year, month, day, hour, min, 0, sec * 1000);
|
159
|
+
if (year < 100) {
|
160
|
+
result.setFullYear(year);
|
161
|
+
}
|
162
|
+
return result;
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.local(year, month = nil, day = nil, hour = nil, min = nil, sec = nil, millisecond = nil)
|
167
|
+
%x{
|
168
|
+
var args, result;
|
169
|
+
|
170
|
+
if (arguments.length === 10) {
|
171
|
+
args = $slice.call(arguments);
|
172
|
+
year = args[5];
|
173
|
+
month = args[4];
|
174
|
+
day = args[3];
|
175
|
+
hour = args[2];
|
176
|
+
min = args[1];
|
177
|
+
sec = args[0];
|
178
|
+
}
|
179
|
+
|
180
|
+
args = time_params(year, month, day, hour, min, sec);
|
181
|
+
year = args[0];
|
182
|
+
month = args[1];
|
183
|
+
day = args[2];
|
184
|
+
hour = args[3];
|
185
|
+
min = args[4];
|
186
|
+
sec = args[5];
|
187
|
+
|
188
|
+
result = new Date(year, month, day, hour, min, 0, sec * 1000);
|
189
|
+
if (year < 100) {
|
190
|
+
result.setFullYear(year);
|
191
|
+
}
|
192
|
+
return result;
|
193
|
+
}
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.gm(year, month = nil, day = nil, hour = nil, min = nil, sec = nil, millisecond = nil)
|
197
|
+
%x{
|
198
|
+
var args, result;
|
199
|
+
|
200
|
+
if (arguments.length === 10) {
|
201
|
+
args = $slice.call(arguments);
|
202
|
+
year = args[5];
|
203
|
+
month = args[4];
|
204
|
+
day = args[3];
|
205
|
+
hour = args[2];
|
206
|
+
min = args[1];
|
207
|
+
sec = args[0];
|
208
|
+
}
|
209
|
+
|
210
|
+
args = time_params(year, month, day, hour, min, sec);
|
211
|
+
year = args[0];
|
212
|
+
month = args[1];
|
213
|
+
day = args[2];
|
214
|
+
hour = args[3];
|
215
|
+
min = args[4];
|
216
|
+
sec = args[5];
|
217
|
+
|
218
|
+
result = new Date(Date.UTC(year, month, day, hour, min, 0, sec * 1000));
|
219
|
+
if (year < 100) {
|
220
|
+
result.setUTCFullYear(year);
|
221
|
+
}
|
222
|
+
result.is_utc = true;
|
223
|
+
return result;
|
224
|
+
}
|
225
|
+
end
|
226
|
+
|
227
|
+
class << self
|
228
|
+
alias mktime local
|
229
|
+
alias utc gm
|
230
|
+
end
|
231
|
+
|
232
|
+
def self.now
|
233
|
+
new
|
234
|
+
end
|
235
|
+
|
236
|
+
def +(other)
|
237
|
+
if Time === other
|
238
|
+
raise TypeError, "time + time?"
|
239
|
+
end
|
240
|
+
|
241
|
+
%x{
|
242
|
+
if (!other.$$is_number) {
|
243
|
+
other = #{Opal.coerce_to!(other, Integer, :to_int)};
|
244
|
+
}
|
245
|
+
var result = new Date(self.getTime() + (other * 1000));
|
246
|
+
result.is_utc = self.is_utc;
|
247
|
+
return result;
|
248
|
+
}
|
249
|
+
end
|
250
|
+
|
251
|
+
def -(other)
|
252
|
+
if Time === other
|
253
|
+
return `(self.getTime() - other.getTime()) / 1000`
|
254
|
+
end
|
255
|
+
|
256
|
+
%x{
|
257
|
+
if (!other.$$is_number) {
|
258
|
+
other = #{Opal.coerce_to!(other, Integer, :to_int)};
|
259
|
+
}
|
260
|
+
var result = new Date(self.getTime() - (other * 1000));
|
261
|
+
result.is_utc = self.is_utc;
|
262
|
+
return result;
|
263
|
+
}
|
264
|
+
end
|
265
|
+
|
266
|
+
def <=>(other)
|
267
|
+
if Time === other
|
268
|
+
to_f <=> other.to_f
|
269
|
+
else
|
270
|
+
r = other <=> self
|
271
|
+
if r.nil?
|
272
|
+
nil
|
273
|
+
elsif r > 0
|
274
|
+
-1
|
275
|
+
elsif r < 0
|
276
|
+
1
|
277
|
+
else
|
278
|
+
0
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def ==(other)
|
284
|
+
`#{to_f} === #{other.to_f}`
|
285
|
+
end
|
286
|
+
|
287
|
+
def asctime
|
288
|
+
strftime '%a %b %e %H:%M:%S %Y'
|
289
|
+
end
|
290
|
+
|
291
|
+
alias ctime asctime
|
292
|
+
|
293
|
+
def day
|
294
|
+
`self.is_utc ? self.getUTCDate() : self.getDate()`
|
295
|
+
end
|
296
|
+
|
297
|
+
def yday
|
298
|
+
%x{
|
299
|
+
// http://javascript.about.com/library/bldayyear.htm
|
300
|
+
var onejan = new Date(self.getFullYear(), 0, 1);
|
301
|
+
return Math.ceil((self - onejan) / 86400000);
|
302
|
+
}
|
303
|
+
end
|
304
|
+
|
305
|
+
def isdst
|
306
|
+
%x{
|
307
|
+
var jan = new Date(self.getFullYear(), 0, 1),
|
308
|
+
jul = new Date(self.getFullYear(), 6, 1);
|
309
|
+
return self.getTimezoneOffset() < Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
|
310
|
+
}
|
311
|
+
end
|
312
|
+
|
313
|
+
alias dst? isdst
|
314
|
+
|
315
|
+
def dup
|
316
|
+
copy = `new Date(self.getTime())`
|
317
|
+
|
318
|
+
copy.copy_instance_variables(self)
|
319
|
+
copy.initialize_dup(self)
|
320
|
+
|
321
|
+
copy
|
322
|
+
end
|
323
|
+
|
324
|
+
def eql?(other)
|
325
|
+
other.is_a?(Time) && (self <=> other).zero?
|
326
|
+
end
|
327
|
+
|
328
|
+
def friday?
|
329
|
+
`#{wday} == 5`
|
330
|
+
end
|
331
|
+
|
332
|
+
def hash
|
333
|
+
`'Time:' + self.getTime()`
|
334
|
+
end
|
335
|
+
|
336
|
+
def hour
|
337
|
+
`self.is_utc ? self.getUTCHours() : self.getHours()`
|
338
|
+
end
|
339
|
+
|
340
|
+
def inspect
|
341
|
+
if utc?
|
342
|
+
strftime '%Y-%m-%d %H:%M:%S UTC'
|
343
|
+
else
|
344
|
+
strftime '%Y-%m-%d %H:%M:%S %z'
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
alias mday day
|
349
|
+
|
350
|
+
def min
|
351
|
+
`self.is_utc ? self.getUTCMinutes() : self.getMinutes()`
|
352
|
+
end
|
353
|
+
|
354
|
+
def mon
|
355
|
+
`(self.is_utc ? self.getUTCMonth() : self.getMonth()) + 1`
|
356
|
+
end
|
357
|
+
|
358
|
+
def monday?
|
359
|
+
`#{wday} == 1`
|
360
|
+
end
|
361
|
+
|
362
|
+
alias month mon
|
363
|
+
|
364
|
+
def saturday?
|
365
|
+
`#{wday} == 6`
|
366
|
+
end
|
367
|
+
|
368
|
+
def sec
|
369
|
+
`self.is_utc ? self.getUTCSeconds() : self.getSeconds()`
|
370
|
+
end
|
371
|
+
|
372
|
+
def succ
|
373
|
+
%x{
|
374
|
+
var result = new Date(self.getTime() + 1000);
|
375
|
+
result.is_utc = self.is_utc;
|
376
|
+
return result;
|
377
|
+
}
|
378
|
+
end
|
379
|
+
|
380
|
+
def usec
|
381
|
+
`self.getMilliseconds() * 1000`
|
382
|
+
end
|
383
|
+
|
384
|
+
def zone
|
385
|
+
%x{
|
386
|
+
var string = self.toString(),
|
387
|
+
result;
|
388
|
+
|
389
|
+
if (string.indexOf('(') == -1) {
|
390
|
+
result = string.match(/[A-Z]{3,4}/)[0];
|
391
|
+
}
|
392
|
+
else {
|
393
|
+
result = string.match(/\([^)]+\)/)[0].match(/[A-Z]/g).join('');
|
394
|
+
}
|
395
|
+
|
396
|
+
if (result == "GMT" && /(GMT\W*\d{4})/.test(string)) {
|
397
|
+
return RegExp.$1;
|
398
|
+
}
|
399
|
+
else {
|
400
|
+
return result;
|
401
|
+
}
|
402
|
+
}
|
403
|
+
end
|
404
|
+
|
405
|
+
def getgm
|
406
|
+
%x{
|
407
|
+
var result = new Date(self.getTime());
|
408
|
+
result.is_utc = true;
|
409
|
+
return result;
|
410
|
+
}
|
411
|
+
end
|
412
|
+
|
413
|
+
alias getutc getgm
|
414
|
+
|
415
|
+
def gmtime
|
416
|
+
%x{
|
417
|
+
self.is_utc = true;
|
418
|
+
return self;
|
419
|
+
}
|
420
|
+
end
|
421
|
+
|
422
|
+
alias utc gmtime
|
423
|
+
|
424
|
+
def gmt?
|
425
|
+
`self.is_utc === true`
|
426
|
+
end
|
427
|
+
|
428
|
+
def gmt_offset
|
429
|
+
`-self.getTimezoneOffset() * 60`
|
430
|
+
end
|
431
|
+
|
432
|
+
def strftime(format)
|
433
|
+
%x{
|
434
|
+
return format.replace(/%([\-_#^0]*:{0,2})(\d+)?([EO]*)(.)/g, function(full, flags, width, _, conv) {
|
435
|
+
var result = "",
|
436
|
+
zero = flags.indexOf('0') !== -1,
|
437
|
+
pad = flags.indexOf('-') === -1,
|
438
|
+
blank = flags.indexOf('_') !== -1,
|
439
|
+
upcase = flags.indexOf('^') !== -1,
|
440
|
+
invert = flags.indexOf('#') !== -1,
|
441
|
+
colons = (flags.match(':') || []).length;
|
442
|
+
|
443
|
+
width = parseInt(width, 10);
|
444
|
+
|
445
|
+
if (zero && blank) {
|
446
|
+
if (flags.indexOf('0') < flags.indexOf('_')) {
|
447
|
+
zero = false;
|
448
|
+
}
|
449
|
+
else {
|
450
|
+
blank = false;
|
451
|
+
}
|
452
|
+
}
|
453
|
+
|
454
|
+
switch (conv) {
|
455
|
+
case 'Y':
|
456
|
+
result += #{year};
|
457
|
+
break;
|
458
|
+
|
459
|
+
case 'C':
|
460
|
+
zero = !blank;
|
461
|
+
result += Math.round(#{year} / 100);
|
462
|
+
break;
|
463
|
+
|
464
|
+
case 'y':
|
465
|
+
zero = !blank;
|
466
|
+
result += (#{year} % 100);
|
467
|
+
break;
|
468
|
+
|
469
|
+
case 'm':
|
470
|
+
zero = !blank;
|
471
|
+
result += #{mon};
|
472
|
+
break;
|
473
|
+
|
474
|
+
case 'B':
|
475
|
+
result += long_months[#{mon} - 1];
|
476
|
+
break;
|
477
|
+
|
478
|
+
case 'b':
|
479
|
+
case 'h':
|
480
|
+
blank = !zero;
|
481
|
+
result += short_months[#{mon} - 1];
|
482
|
+
break;
|
483
|
+
|
484
|
+
case 'd':
|
485
|
+
zero = !blank
|
486
|
+
result += #{day};
|
487
|
+
break;
|
488
|
+
|
489
|
+
case 'e':
|
490
|
+
blank = !zero
|
491
|
+
result += #{day};
|
492
|
+
break;
|
493
|
+
|
494
|
+
case 'j':
|
495
|
+
result += #{yday};
|
496
|
+
break;
|
497
|
+
|
498
|
+
case 'H':
|
499
|
+
zero = !blank;
|
500
|
+
result += #{hour};
|
501
|
+
break;
|
502
|
+
|
503
|
+
case 'k':
|
504
|
+
blank = !zero;
|
505
|
+
result += #{hour};
|
506
|
+
break;
|
507
|
+
|
508
|
+
case 'I':
|
509
|
+
zero = !blank;
|
510
|
+
result += (#{hour} % 12 || 12);
|
511
|
+
break;
|
512
|
+
|
513
|
+
case 'l':
|
514
|
+
blank = !zero;
|
515
|
+
result += (#{hour} % 12 || 12);
|
516
|
+
break;
|
517
|
+
|
518
|
+
case 'P':
|
519
|
+
result += (#{hour} >= 12 ? "pm" : "am");
|
520
|
+
break;
|
521
|
+
|
522
|
+
case 'p':
|
523
|
+
result += (#{hour} >= 12 ? "PM" : "AM");
|
524
|
+
break;
|
525
|
+
|
526
|
+
case 'M':
|
527
|
+
zero = !blank;
|
528
|
+
result += #{min};
|
529
|
+
break;
|
530
|
+
|
531
|
+
case 'S':
|
532
|
+
zero = !blank;
|
533
|
+
result += #{sec}
|
534
|
+
break;
|
535
|
+
|
536
|
+
case 'L':
|
537
|
+
zero = !blank;
|
538
|
+
width = isNaN(width) ? 3 : width;
|
539
|
+
result += self.getMilliseconds();
|
540
|
+
break;
|
541
|
+
|
542
|
+
case 'N':
|
543
|
+
width = isNaN(width) ? 9 : width;
|
544
|
+
result += #{`self.getMilliseconds().toString()`.rjust(3, '0')};
|
545
|
+
result = #{`result`.ljust(`width`, '0')};
|
546
|
+
break;
|
547
|
+
|
548
|
+
case 'z':
|
549
|
+
var offset = self.getTimezoneOffset(),
|
550
|
+
hours = Math.floor(Math.abs(offset) / 60),
|
551
|
+
minutes = Math.abs(offset) % 60;
|
552
|
+
|
553
|
+
result += offset < 0 ? "+" : "-";
|
554
|
+
result += hours < 10 ? "0" : "";
|
555
|
+
result += hours;
|
556
|
+
|
557
|
+
if (colons > 0) {
|
558
|
+
result += ":";
|
559
|
+
}
|
560
|
+
|
561
|
+
result += minutes < 10 ? "0" : "";
|
562
|
+
result += minutes;
|
563
|
+
|
564
|
+
if (colons > 1) {
|
565
|
+
result += ":00";
|
566
|
+
}
|
567
|
+
|
568
|
+
break;
|
569
|
+
|
570
|
+
case 'Z':
|
571
|
+
result += #{zone};
|
572
|
+
break;
|
573
|
+
|
574
|
+
case 'A':
|
575
|
+
result += days_of_week[#{wday}];
|
576
|
+
break;
|
577
|
+
|
578
|
+
case 'a':
|
579
|
+
result += short_days[#{wday}];
|
580
|
+
break;
|
581
|
+
|
582
|
+
case 'u':
|
583
|
+
result += (#{wday} + 1);
|
584
|
+
break;
|
585
|
+
|
586
|
+
case 'w':
|
587
|
+
result += #{wday};
|
588
|
+
break;
|
589
|
+
|
590
|
+
case 'V':
|
591
|
+
result += #{cweek_cyear[0].to_s.rjust(2, "0")};
|
592
|
+
break;
|
593
|
+
|
594
|
+
case 'G':
|
595
|
+
result += #{cweek_cyear[1]};
|
596
|
+
break;
|
597
|
+
|
598
|
+
case 'g':
|
599
|
+
result += #{cweek_cyear[1][-2..-1]};
|
600
|
+
break;
|
601
|
+
|
602
|
+
case 's':
|
603
|
+
result += #{to_i};
|
604
|
+
break;
|
605
|
+
|
606
|
+
case 'n':
|
607
|
+
result += "\n";
|
608
|
+
break;
|
609
|
+
|
610
|
+
case 't':
|
611
|
+
result += "\t";
|
612
|
+
break;
|
613
|
+
|
614
|
+
case '%':
|
615
|
+
result += "%";
|
616
|
+
break;
|
617
|
+
|
618
|
+
case 'c':
|
619
|
+
result += #{strftime('%a %b %e %T %Y')};
|
620
|
+
break;
|
621
|
+
|
622
|
+
case 'D':
|
623
|
+
case 'x':
|
624
|
+
result += #{strftime('%m/%d/%y')};
|
625
|
+
break;
|
626
|
+
|
627
|
+
case 'F':
|
628
|
+
result += #{strftime('%Y-%m-%d')};
|
629
|
+
break;
|
630
|
+
|
631
|
+
case 'v':
|
632
|
+
result += #{strftime('%e-%^b-%4Y')};
|
633
|
+
break;
|
634
|
+
|
635
|
+
case 'r':
|
636
|
+
result += #{strftime('%I:%M:%S %p')};
|
637
|
+
break;
|
638
|
+
|
639
|
+
case 'R':
|
640
|
+
result += #{strftime('%H:%M')};
|
641
|
+
break;
|
642
|
+
|
643
|
+
case 'T':
|
644
|
+
case 'X':
|
645
|
+
result += #{strftime('%H:%M:%S')};
|
646
|
+
break;
|
647
|
+
|
648
|
+
default:
|
649
|
+
return full;
|
650
|
+
}
|
651
|
+
|
652
|
+
if (upcase) {
|
653
|
+
result = result.toUpperCase();
|
654
|
+
}
|
655
|
+
|
656
|
+
if (invert) {
|
657
|
+
result = result.replace(/[A-Z]/, function(c) { c.toLowerCase() }).
|
658
|
+
replace(/[a-z]/, function(c) { c.toUpperCase() });
|
659
|
+
}
|
660
|
+
|
661
|
+
if (pad && (zero || blank)) {
|
662
|
+
result = #{`result`.rjust(`isNaN(width) ? 2 : width`, `blank ? " " : "0"`)};
|
663
|
+
}
|
664
|
+
|
665
|
+
return result;
|
666
|
+
});
|
667
|
+
}
|
668
|
+
end
|
669
|
+
|
670
|
+
def sunday?
|
671
|
+
`#{wday} == 0`
|
672
|
+
end
|
673
|
+
|
674
|
+
def thursday?
|
675
|
+
`#{wday} == 4`
|
676
|
+
end
|
677
|
+
|
678
|
+
def to_a
|
679
|
+
[sec, min, hour, day, month, year, wday, yday, isdst, zone]
|
680
|
+
end
|
681
|
+
|
682
|
+
def to_f
|
683
|
+
`self.getTime() / 1000`
|
684
|
+
end
|
685
|
+
|
686
|
+
def to_i
|
687
|
+
`parseInt(self.getTime() / 1000, 10)`
|
688
|
+
end
|
689
|
+
|
690
|
+
alias to_s inspect
|
691
|
+
|
692
|
+
def tuesday?
|
693
|
+
`#{wday} == 2`
|
694
|
+
end
|
695
|
+
|
696
|
+
alias tv_sec sec
|
697
|
+
|
698
|
+
alias tv_usec usec
|
699
|
+
|
700
|
+
alias utc? gmt?
|
701
|
+
|
702
|
+
alias gmtoff gmt_offset
|
703
|
+
alias utc_offset gmt_offset
|
704
|
+
|
705
|
+
def wday
|
706
|
+
`self.is_utc ? self.getUTCDay() : self.getDay()`
|
707
|
+
end
|
708
|
+
|
709
|
+
def wednesday?
|
710
|
+
`#{wday} == 3`
|
711
|
+
end
|
712
|
+
|
713
|
+
def year
|
714
|
+
`self.is_utc ? self.getUTCFullYear() : self.getFullYear()`
|
715
|
+
end
|
716
|
+
|
717
|
+
def cweek_cyear
|
718
|
+
jan01 = Time.new(self.year, 1, 1)
|
719
|
+
jan01_wday = jan01.wday
|
720
|
+
first_monday = 0
|
721
|
+
year = self.year
|
722
|
+
if jan01_wday <= 4 && jan01_wday != 0
|
723
|
+
#Jan 01 is in the first week of the year
|
724
|
+
offset = jan01_wday-1
|
725
|
+
else
|
726
|
+
#Jan 01 is in the last week of the previous year
|
727
|
+
offset = jan01_wday-7-1
|
728
|
+
offset = -1 if offset == -8 #Adjust if Jan 01 is a Sunday
|
729
|
+
end
|
730
|
+
|
731
|
+
week = ((self.yday+offset)/7.00).ceil
|
732
|
+
|
733
|
+
if week <= 0
|
734
|
+
#Get the last week of the previous year
|
735
|
+
return Time.new(self.year-1, 12, 31).cweek_cyear
|
736
|
+
elsif week == 53
|
737
|
+
#Find out whether this is actually week 53 or already week 01 of the following year
|
738
|
+
dec31 = Time.new(self.year, 12, 31)
|
739
|
+
dec31_wday = dec31.wday
|
740
|
+
if dec31_wday <= 3 && dec31_wday != 0
|
741
|
+
week = 1
|
742
|
+
year += 1
|
743
|
+
end
|
744
|
+
end
|
745
|
+
|
746
|
+
[week, year]
|
747
|
+
|
748
|
+
end
|
749
|
+
end
|