puppet 4.7.1-x64-mingw32 → 4.8.0-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- data/Gemfile +0 -3
- data/MAINTAINERS +76 -0
- data/README.md +0 -6
- data/Rakefile +2 -2
- data/lib/puppet/agent.rb +3 -3
- data/lib/puppet/application/apply.rb +1 -1
- data/lib/puppet/configurer.rb +2 -2
- data/lib/puppet/data_providers.rb +1 -0
- data/lib/puppet/data_providers/data_adapter.rb +1 -0
- data/lib/puppet/data_providers/data_function_support.rb +1 -0
- data/lib/puppet/data_providers/function_env_data_provider.rb +1 -0
- data/lib/puppet/data_providers/function_module_data_provider.rb +1 -0
- data/lib/puppet/data_providers/hiera_config.rb +1 -0
- data/lib/puppet/data_providers/hiera_env_data_provider.rb +1 -0
- data/lib/puppet/data_providers/hiera_interpolate.rb +1 -0
- data/lib/puppet/data_providers/hiera_module_data_provider.rb +1 -0
- data/lib/puppet/data_providers/hiera_support.rb +1 -2
- data/lib/puppet/data_providers/json_data_provider_factory.rb +2 -0
- data/lib/puppet/data_providers/yaml_data_provider_factory.rb +2 -0
- data/lib/puppet/defaults.rb +20 -1
- data/lib/puppet/environments.rb +5 -2
- data/lib/puppet/face/catalog.rb +1 -1
- data/lib/puppet/face/epp.rb +57 -11
- data/lib/puppet/face/module/install.rb +6 -6
- data/lib/puppet/functions.rb +23 -24
- data/lib/puppet/functions/alert.rb +14 -0
- data/lib/puppet/functions/binary_file.rb +25 -0
- data/lib/puppet/functions/break.rb +22 -0
- data/lib/puppet/functions/contain.rb +33 -0
- data/lib/puppet/functions/crit.rb +14 -0
- data/lib/puppet/functions/debug.rb +14 -0
- data/lib/puppet/functions/emerg.rb +14 -0
- data/lib/puppet/functions/epp.rb +1 -1
- data/lib/puppet/functions/err.rb +14 -0
- data/lib/puppet/functions/find_file.rb +31 -0
- data/lib/puppet/functions/include.rb +21 -0
- data/lib/puppet/functions/info.rb +14 -0
- data/lib/puppet/functions/new.rb +1 -1
- data/lib/puppet/functions/next.rb +23 -0
- data/lib/puppet/functions/notice.rb +14 -0
- data/lib/puppet/functions/regsubst.rb +12 -16
- data/lib/puppet/functions/require.rb +37 -0
- data/lib/puppet/functions/return.rb +22 -0
- data/lib/puppet/functions/strftime.rb +35 -0
- data/lib/puppet/functions/warning.rb +14 -0
- data/lib/puppet/generate/models/type/type.rb +4 -0
- data/lib/puppet/generate/templates/type/pcore.erb +2 -1
- data/lib/puppet/indirector/face.rb +6 -1
- data/lib/puppet/network/http/error.rb +2 -2
- data/lib/puppet/network/http/handler.rb +2 -2
- data/lib/puppet/node/environment.rb +11 -0
- data/lib/puppet/parser/ast.rb +5 -0
- data/lib/puppet/parser/ast/pops_bridge.rb +17 -4
- data/lib/puppet/parser/compiler.rb +29 -1
- data/lib/puppet/parser/functions.rb +6 -0
- data/lib/puppet/parser/functions/assert_type.rb +1 -1
- data/lib/puppet/parser/functions/binary_file.rb +24 -0
- data/lib/puppet/parser/functions/break.rb +39 -0
- data/lib/puppet/parser/functions/contain.rb +7 -15
- data/lib/puppet/parser/functions/defined.rb +2 -2
- data/lib/puppet/parser/functions/dig.rb +1 -1
- data/lib/puppet/parser/functions/each.rb +1 -1
- data/lib/puppet/parser/functions/epp.rb +2 -2
- data/lib/puppet/parser/functions/filter.rb +1 -1
- data/lib/puppet/parser/functions/find_file.rb +28 -0
- data/lib/puppet/parser/functions/hiera.rb +4 -4
- data/lib/puppet/parser/functions/hiera_array.rb +1 -1
- data/lib/puppet/parser/functions/hiera_hash.rb +1 -1
- data/lib/puppet/parser/functions/hiera_include.rb +1 -1
- data/lib/puppet/parser/functions/include.rb +4 -8
- data/lib/puppet/parser/functions/inline_epp.rb +1 -1
- data/lib/puppet/parser/functions/lest.rb +1 -1
- data/lib/puppet/parser/functions/lookup.rb +4 -2
- data/lib/puppet/parser/functions/map.rb +1 -1
- data/lib/puppet/parser/functions/match.rb +1 -1
- data/lib/puppet/parser/functions/new.rb +414 -18
- data/lib/puppet/parser/functions/next.rb +38 -0
- data/lib/puppet/parser/functions/reduce.rb +1 -1
- data/lib/puppet/parser/functions/regsubst.rb +4 -2
- data/lib/puppet/parser/functions/require.rb +4 -27
- data/lib/puppet/parser/functions/return.rb +71 -0
- data/lib/puppet/parser/functions/reverse_each.rb +1 -1
- data/lib/puppet/parser/functions/scanf.rb +13 -8
- data/lib/puppet/parser/functions/slice.rb +1 -1
- data/lib/puppet/parser/functions/split.rb +1 -1
- data/lib/puppet/parser/functions/step.rb +1 -1
- data/lib/puppet/parser/functions/strftime.rb +185 -0
- data/lib/puppet/parser/functions/then.rb +1 -1
- data/lib/puppet/parser/functions/type.rb +1 -1
- data/lib/puppet/parser/functions/with.rb +3 -3
- data/lib/puppet/parser/resource.rb +8 -5
- data/lib/puppet/parser/scope.rb +1 -1
- data/lib/puppet/plugins/configuration.rb +8 -0
- data/lib/puppet/plugins/data_providers.rb +1 -0
- data/lib/puppet/plugins/data_providers/data_provider.rb +7 -28
- data/lib/puppet/plugins/data_providers/registry.rb +1 -0
- data/lib/puppet/pops.rb +4 -0
- data/lib/puppet/pops/evaluator/access_operator.rb +36 -5
- data/lib/puppet/pops/evaluator/closure.rb +81 -12
- data/lib/puppet/pops/evaluator/compare_operator.rb +24 -1
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +29 -5
- data/lib/puppet/pops/evaluator/json_strict_literal_evaluator.rb +1 -1
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +53 -62
- data/lib/puppet/pops/evaluator/runtime3_support.rb +15 -6
- data/lib/puppet/pops/functions/dispatch.rb +9 -2
- data/lib/puppet/pops/functions/dispatcher.rb +3 -1
- data/lib/puppet/pops/functions/function.rb +19 -2
- data/lib/puppet/pops/issues.rb +9 -0
- data/lib/puppet/pops/label_provider.rb +2 -2
- data/lib/puppet/pops/loader/loader.rb +17 -0
- data/lib/puppet/pops/loader/static_loader.rb +0 -41
- data/lib/puppet/pops/lookup.rb +12 -0
- data/lib/puppet/pops/lookup/context.rb +86 -0
- data/lib/puppet/pops/lookup/explainer.rb +46 -6
- data/lib/puppet/pops/lookup/invocation.rb +19 -0
- data/lib/puppet/pops/lookup/sub_lookup.rb +1 -1
- data/lib/puppet/pops/model/factory.rb +20 -8
- data/lib/puppet/pops/model/model_label_provider.rb +3 -0
- data/lib/puppet/pops/model/model_meta.rb +2 -0
- data/lib/puppet/pops/model/model_tree_dumper.rb +14 -0
- data/lib/puppet/pops/parser/egrammar.ra +11 -6
- data/lib/puppet/pops/parser/eparser.rb +1112 -1086
- data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
- data/lib/puppet/pops/pcore.rb +1 -0
- data/lib/puppet/pops/puppet_stack.rb +3 -3
- data/lib/puppet/pops/resource/param.rb +5 -1
- data/lib/puppet/pops/resource/resource_type_impl.rb +8 -4
- data/lib/puppet/pops/resource/resource_type_set.pcore +1 -0
- data/lib/puppet/pops/serialization/abstract_reader.rb +19 -2
- data/lib/puppet/pops/serialization/abstract_writer.rb +16 -3
- data/lib/puppet/pops/serialization/deserializer.rb +5 -1
- data/lib/puppet/pops/serialization/extension.rb +2 -0
- data/lib/puppet/pops/serialization/json.rb +76 -26
- data/lib/puppet/pops/serialization/serializer.rb +5 -1
- data/lib/puppet/pops/serialization/time_factory.rb +2 -1
- data/lib/puppet/pops/time/timespan.rb +718 -0
- data/lib/puppet/pops/time/timestamp.rb +148 -0
- data/lib/puppet/pops/types/p_binary_type.rb +220 -0
- data/lib/puppet/pops/types/p_object_type.rb +12 -6
- data/lib/puppet/pops/types/p_sensitive_type.rb +5 -1
- data/lib/puppet/pops/types/p_timespan_type.rb +141 -0
- data/lib/puppet/pops/types/p_timestamp_type.rb +69 -0
- data/lib/puppet/pops/types/string_converter.rb +62 -0
- data/lib/puppet/pops/types/type_asserter.rb +1 -1
- data/lib/puppet/pops/types/type_calculator.rb +17 -3
- data/lib/puppet/pops/types/type_factory.rb +35 -1
- data/lib/puppet/pops/types/type_formatter.rb +64 -11
- data/lib/puppet/pops/types/type_mismatch_describer.rb +110 -61
- data/lib/puppet/pops/types/type_parser.rb +18 -4
- data/lib/puppet/pops/types/types.rb +98 -63
- data/lib/puppet/pops/validation.rb +9 -1
- data/lib/puppet/pops/validation/checker4_0.rb +7 -0
- data/lib/puppet/property.rb +1 -1
- data/lib/puppet/provider.rb +3 -6
- data/lib/puppet/provider/mcx/mcxcontent.rb +1 -1
- data/lib/puppet/provider/mount/parsed.rb +18 -4
- data/lib/puppet/provider/nameservice/directoryservice.rb +15 -7
- data/lib/puppet/provider/package/gem.rb +6 -1
- data/lib/puppet/provider/package/pip.rb +0 -1
- data/lib/puppet/provider/package/pkg.rb +5 -1
- data/lib/puppet/provider/package/pkgng.rb +1 -1
- data/lib/puppet/provider/package/yum.rb +10 -0
- data/lib/puppet/provider/service/launchd.rb +1 -0
- data/lib/puppet/provider/user/directoryservice.rb +6 -6
- data/lib/puppet/provider/yumrepo/inifile.rb +1 -1
- data/lib/puppet/provider/zpool/zpool.rb +1 -1
- data/lib/puppet/resource.rb +54 -12
- data/lib/puppet/resource/capability_finder.rb +15 -9
- data/lib/puppet/resource/catalog.rb +25 -6
- data/lib/puppet/resource/type.rb +3 -1
- data/lib/puppet/settings.rb +1 -1
- data/lib/puppet/settings/environment_conf.rb +12 -4
- data/lib/puppet/syntax_checkers/base64.rb +41 -0
- data/lib/puppet/syntax_checkers/json.rb +0 -2
- data/lib/puppet/transaction.rb +6 -0
- data/lib/puppet/transaction/additional_resource_generator.rb +5 -0
- data/lib/puppet/transaction/report.rb +7 -2
- data/lib/puppet/type.rb +2 -1
- data/lib/puppet/type/file/checksum.rb +1 -0
- data/lib/puppet/type/file/content.rb +4 -4
- data/lib/puppet/type/mount.rb +44 -0
- data/lib/puppet/type/ssh_authorized_key.rb +1 -1
- data/lib/puppet/type/tidy.rb +3 -0
- data/lib/puppet/type/user.rb +12 -6
- data/lib/puppet/util/log.rb +25 -0
- data/lib/puppet/util/plist.rb +8 -3
- data/lib/puppet/version.rb +1 -1
- data/lib/puppet_x.rb +7 -1
- data/spec/integration/application/apply_spec.rb +118 -0
- data/spec/integration/parser/compiler_spec.rb +28 -0
- data/spec/integration/parser/pcore_resource_spec.rb +40 -3
- data/spec/integration/provider/mount_spec.rb +2 -1
- data/spec/integration/util/windows/principal_spec.rb +2 -2
- data/spec/integration/util/windows/registry_spec.rb +4 -4
- data/spec/lib/puppet_spec/compiler.rb +5 -1
- data/spec/lib/puppet_spec/unindent.rb +5 -0
- data/spec/shared_contexts/types_setup.rb +6 -0
- data/spec/shared_examples/rhel_package_provider.rb +16 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/agent_spec.rb +11 -0
- data/spec/unit/application/lookup_spec.rb +94 -3
- data/spec/unit/capability_spec.rb +22 -0
- data/spec/unit/configurer_spec.rb +8 -0
- data/spec/unit/face/epp_face_spec.rb +22 -3
- data/spec/unit/functions/assert_type_spec.rb +3 -3
- data/spec/unit/functions/binary_file_spec.rb +46 -0
- data/spec/unit/functions/break_spec.rb +89 -0
- data/spec/unit/{parser/functions → functions}/contain_spec.rb +68 -3
- data/spec/unit/functions/find_file_spec.rb +69 -0
- data/spec/unit/functions/include_spec.rb +175 -0
- data/spec/unit/functions/logging_spec.rb +54 -0
- data/spec/unit/functions/lookup_spec.rb +3 -3
- data/spec/unit/functions/new_spec.rb +105 -5
- data/spec/unit/functions/next_spec.rb +93 -0
- data/spec/unit/functions/require_spec.rb +83 -0
- data/spec/unit/functions/return_spec.rb +105 -0
- data/spec/unit/{parser/functions → functions}/shared.rb +14 -11
- data/spec/unit/functions/strftime_spec.rb +152 -0
- data/spec/unit/functions4_spec.rb +22 -0
- data/spec/unit/indirector/face_spec.rb +10 -2
- data/spec/unit/network/http/error_spec.rb +1 -2
- data/spec/unit/network/http/handler_spec.rb +6 -5
- data/spec/unit/parser/functions/hiera_array_spec.rb +1 -1
- data/spec/unit/parser/functions/hiera_hash_spec.rb +1 -1
- data/spec/unit/parser/functions/hiera_include_spec.rb +1 -1
- data/spec/unit/parser/functions/hiera_spec.rb +1 -1
- data/spec/unit/parser/functions/lookup_spec.rb +1 -1
- data/spec/unit/parser/functions/regsubst_spec.rb +1 -1
- data/spec/unit/parser/functions/split_spec.rb +1 -1
- data/spec/unit/pops/evaluator/access_ops_spec.rb +81 -1
- data/spec/unit/pops/evaluator/arithmetic_ops_spec.rb +170 -0
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +29 -4
- data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +112 -4
- data/spec/unit/pops/loaders/dependency_loader_spec.rb +12 -0
- data/spec/unit/pops/loaders/static_loader_spec.rb +0 -26
- data/spec/unit/pops/lookup/context_spec.rb +149 -0
- data/spec/unit/pops/parser/parse_functions_spec.rb +19 -0
- data/spec/unit/pops/parser/parse_lambda_spec.rb +19 -0
- data/spec/unit/pops/puppet_stack_spec.rb +1 -1
- data/spec/unit/pops/resource/resource_type_impl_spec.rb +74 -0
- data/spec/unit/pops/serialization/packer_spec.rb +34 -14
- data/spec/unit/pops/serialization/serialization_spec.rb +67 -5
- data/spec/unit/pops/time/timespan_spec.rb +121 -0
- data/spec/unit/pops/types/p_binary_type_spec.rb +243 -0
- data/spec/unit/pops/types/p_object_type_spec.rb +7 -7
- data/spec/unit/pops/types/p_sensitive_type_spec.rb +1 -1
- data/spec/unit/pops/types/p_timespan_type_spec.rb +273 -0
- data/spec/unit/pops/types/p_timestamp_type_spec.rb +311 -0
- data/spec/unit/pops/types/p_type_set_type_spec.rb +13 -13
- data/spec/unit/pops/types/ruby_generator_spec.rb +12 -12
- data/spec/unit/pops/types/string_converter_spec.rb +89 -0
- data/spec/unit/pops/types/type_asserter_spec.rb +3 -3
- data/spec/unit/pops/types/type_calculator_spec.rb +113 -5
- data/spec/unit/pops/types/type_formatter_spec.rb +40 -0
- data/spec/unit/pops/types/type_mismatch_describer_spec.rb +49 -38
- data/spec/unit/pops/types/type_parser_spec.rb +87 -4
- data/spec/unit/pops/types/types_spec.rb +1 -1
- data/spec/unit/pops/validator/validator_spec.rb +23 -0
- data/spec/unit/provider/mount/parsed_spec.rb +47 -29
- data/spec/unit/provider/package/pkg_spec.rb +109 -99
- data/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +1 -0
- data/spec/unit/provider/user/aix_spec.rb +1 -1
- data/spec/unit/provider/user/directoryservice_spec.rb +101 -30
- data/spec/unit/resource/capability_finder_spec.rb +29 -7
- data/spec/unit/resource/catalog_spec.rb +127 -0
- data/spec/unit/ssl/certificate_request_spec.rb +1 -1
- data/spec/unit/transaction/additional_resource_generator_spec.rb +30 -0
- data/spec/unit/transaction/persistence_spec.rb +1 -6
- data/spec/unit/transaction/report_spec.rb +23 -0
- data/spec/unit/transaction_spec.rb +38 -0
- data/spec/unit/type/mount_spec.rb +5 -0
- data/spec/unit/util/plist_spec.rb +14 -2
- metadata +71 -12
- data/spec/integration/parser/functions/require_spec.rb +0 -43
- data/spec/unit/parser/functions/include_spec.rb +0 -55
- data/spec/unit/parser/functions/require_spec.rb +0 -68
@@ -4,7 +4,8 @@ module Serialization
|
|
4
4
|
# the created Time object can be serialized and deserialized using its
|
5
5
|
# seconds and nanoseconds without loss of precision.
|
6
6
|
#
|
7
|
-
# @
|
7
|
+
# @deprecated No longer in use. Functionality replaced by Timestamp
|
8
|
+
# @api private
|
8
9
|
class TimeFactory
|
9
10
|
|
10
11
|
NANO_DENOMINATOR = 10**9
|
@@ -0,0 +1,718 @@
|
|
1
|
+
module Puppet::Pops
|
2
|
+
module Time
|
3
|
+
NSECS_PER_USEC = 1000
|
4
|
+
NSECS_PER_MSEC = NSECS_PER_USEC * 1000
|
5
|
+
NSECS_PER_SEC = NSECS_PER_MSEC * 1000
|
6
|
+
NSECS_PER_MIN = NSECS_PER_SEC * 60
|
7
|
+
NSECS_PER_HOUR = NSECS_PER_MIN * 60
|
8
|
+
NSECS_PER_DAY = NSECS_PER_HOUR * 24
|
9
|
+
|
10
|
+
KEY_STRING = 'string'.freeze
|
11
|
+
KEY_FORMAT = 'format'.freeze
|
12
|
+
KEY_NEGATIVE = 'negative'.freeze
|
13
|
+
KEY_DAYS = 'days'.freeze
|
14
|
+
KEY_HOURS = 'hours'.freeze
|
15
|
+
KEY_MINUTES = 'minutes'.freeze
|
16
|
+
KEY_SECONDS = 'seconds'.freeze
|
17
|
+
KEY_MILLISECONDS = 'milliseconds'.freeze
|
18
|
+
KEY_MICROSECONDS = 'microseconds'.freeze
|
19
|
+
KEY_NANOSECONDS = 'nanoseconds'.freeze
|
20
|
+
|
21
|
+
# TimeData is a Numeric that stores its value internally as nano-seconds but will be considered to be seconds and fractions of
|
22
|
+
# seconds when used in arithmetic or comparison with other Numeric types.
|
23
|
+
#
|
24
|
+
class TimeData < Numeric
|
25
|
+
include LabelProvider
|
26
|
+
|
27
|
+
attr_reader :nsecs
|
28
|
+
|
29
|
+
def initialize(nanoseconds)
|
30
|
+
@nsecs = nanoseconds
|
31
|
+
end
|
32
|
+
|
33
|
+
def <=>(o)
|
34
|
+
case o
|
35
|
+
when self.class
|
36
|
+
@nsecs <=> o.nsecs
|
37
|
+
when Integer
|
38
|
+
to_int <=> o
|
39
|
+
when Float
|
40
|
+
to_f <=> o
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def label(o)
|
47
|
+
Utils.name_to_segments(o.class.name).last
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Float] the number of seconds
|
51
|
+
def to_f
|
52
|
+
@nsecs.fdiv(NSECS_PER_SEC)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Integer] the number of seconds with fraction part truncated
|
56
|
+
def to_int
|
57
|
+
@nsecs / NSECS_PER_SEC
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_i
|
61
|
+
to_int
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Complex] short for `#to_f.to_c`
|
65
|
+
def to_c
|
66
|
+
to_f.to_c
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Rational] initial numerator is nano-seconds and denominator is nano-seconds per second
|
70
|
+
def to_r
|
71
|
+
Rational(@nsecs, NSECS_PER_SEC)
|
72
|
+
end
|
73
|
+
|
74
|
+
undef_method :phase, :polar, :rect, :rectangular
|
75
|
+
end
|
76
|
+
|
77
|
+
class Timespan < TimeData
|
78
|
+
def self.from_fields(negative, days, hours, minutes, seconds, milliseconds = 0, microseconds = 0, nanoseconds = 0)
|
79
|
+
ns = (((((days * 24 + hours) * 60 + minutes) * 60 + seconds) * 1000 + milliseconds) * 1000 + microseconds) * 1000 + nanoseconds
|
80
|
+
new(negative ? -ns : ns)
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.from_hash(hash)
|
84
|
+
hash.include?('string') ? from_string_hash(hash) : from_fields_hash(hash)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.from_string_hash(hash)
|
88
|
+
parse(hash[KEY_STRING], hash[KEY_FORMAT] || Format::DEFAULTS)
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.from_fields_hash(hash)
|
92
|
+
from_fields(
|
93
|
+
hash[KEY_NEGATIVE] || false,
|
94
|
+
hash[KEY_DAYS] || 0,
|
95
|
+
hash[KEY_HOURS] || 0,
|
96
|
+
hash[KEY_MINUTES] || 0,
|
97
|
+
hash[KEY_SECONDS] || 0,
|
98
|
+
hash[KEY_MILLISECONDS] || 0,
|
99
|
+
hash[KEY_MICROSECONDS] || 0,
|
100
|
+
hash[KEY_NANOSECONDS] || 0)
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.parse(str, format = Format::DEFAULTS)
|
104
|
+
if format.is_a?(::Array)
|
105
|
+
format.each do |fmt|
|
106
|
+
fmt = FormatParser.singleton.parse_format(fmt) unless fmt.is_a?(Format)
|
107
|
+
begin
|
108
|
+
return fmt.parse(str)
|
109
|
+
rescue ArgumentError
|
110
|
+
end
|
111
|
+
end
|
112
|
+
raise ArgumentError, "Unable to parse '#{str}' using any of the formats #{format.join(', ')}"
|
113
|
+
end
|
114
|
+
format = FormatParser.singleton.parse_format(format) unless format.is_a?(Format)
|
115
|
+
format.parse(str)
|
116
|
+
end
|
117
|
+
|
118
|
+
# @return [true] if the stored value is negative
|
119
|
+
def negative?
|
120
|
+
@nsecs < 0
|
121
|
+
end
|
122
|
+
|
123
|
+
def +(o)
|
124
|
+
case o
|
125
|
+
when Timestamp
|
126
|
+
Timestamp.new(@nsecs + o.nsecs)
|
127
|
+
when Timespan
|
128
|
+
Timespan.new(@nsecs + o.nsecs)
|
129
|
+
when Integer, Float
|
130
|
+
# Add seconds
|
131
|
+
Timespan.new(@nsecs + (o * NSECS_PER_SEC).to_i)
|
132
|
+
else
|
133
|
+
raise ArgumentError, "#{a_an_uc(o)} cannot be added to a Timespan" unless o.is_a?(Timespan)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def -(o)
|
138
|
+
case o
|
139
|
+
when Timespan
|
140
|
+
Timespan.new(@nsecs - o.nsecs)
|
141
|
+
when Integer, Float
|
142
|
+
# Subtract seconds
|
143
|
+
Timespan.new(@nsecs - (o * NSECS_PER_SEC).to_i)
|
144
|
+
else
|
145
|
+
raise ArgumentError, "#{a_an_uc(o)} cannot be subtracted from a Timespan"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def -@
|
150
|
+
Timespan.new(-@nsecs)
|
151
|
+
end
|
152
|
+
|
153
|
+
def *(o)
|
154
|
+
case o
|
155
|
+
when Integer, Float
|
156
|
+
Timespan.new((@nsecs * o).to_i)
|
157
|
+
else
|
158
|
+
raise ArgumentError, "A Timestamp cannot be multiplied by #{a_an(o)}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def divmod(o)
|
163
|
+
case o
|
164
|
+
when Integer
|
165
|
+
to_i.divmod(o)
|
166
|
+
when Float
|
167
|
+
to_f.divmod(o)
|
168
|
+
else
|
169
|
+
raise ArgumentError, "Can not do modulus on a Timespan using a #{a_an(o)}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def modulo(o)
|
174
|
+
divmod(o)[1]
|
175
|
+
end
|
176
|
+
|
177
|
+
def %(o)
|
178
|
+
modulo(o)
|
179
|
+
end
|
180
|
+
|
181
|
+
def div(o)
|
182
|
+
case o
|
183
|
+
when Timespan
|
184
|
+
# Timespan/Timespan yields a Float
|
185
|
+
@nsecs.fdiv(o.nsecs)
|
186
|
+
when Integer, Float
|
187
|
+
Timespan.new(@nsecs.div(o))
|
188
|
+
else
|
189
|
+
raise ArgumentError, "A Timespan cannot be divided by #{a_an(o)}"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def /(o)
|
194
|
+
div(o)
|
195
|
+
end
|
196
|
+
|
197
|
+
# @return [Integer] a positive integer denoting the number of days
|
198
|
+
def days
|
199
|
+
total_days
|
200
|
+
end
|
201
|
+
|
202
|
+
# @return [Integer] a positive integer, 0 - 23 denoting hours of day
|
203
|
+
def hours
|
204
|
+
total_hours % 24
|
205
|
+
end
|
206
|
+
|
207
|
+
# @return [Integer] a positive integer, 0 - 59 denoting minutes of hour
|
208
|
+
def minutes
|
209
|
+
total_minutes % 60
|
210
|
+
end
|
211
|
+
|
212
|
+
# @return [Integer] a positive integer, 0 - 59 denoting seconds of minute
|
213
|
+
def seconds
|
214
|
+
total_seconds % 60
|
215
|
+
end
|
216
|
+
|
217
|
+
# @return [Integer] a positive integer, 0 - 999 denoting milliseconds of second
|
218
|
+
def milliseconds
|
219
|
+
total_milliseconds % 1000
|
220
|
+
end
|
221
|
+
|
222
|
+
# @return [Integer] a positive integer, 0 - 999.999.999 denoting nanoseconds of second
|
223
|
+
def nanoseconds
|
224
|
+
total_nanoseconds % NSECS_PER_SEC
|
225
|
+
end
|
226
|
+
|
227
|
+
# Formats this timestamp into a string according to the given `format`
|
228
|
+
#
|
229
|
+
# @param [String,Format] format The format to use when producing the string
|
230
|
+
# @return [String] the string representing the formatted timestamp
|
231
|
+
# @raise [ArgumentError] if the format is a string with illegal format characters
|
232
|
+
# @api public
|
233
|
+
def format(format)
|
234
|
+
format = FormatParser.singleton.parse_format(format) unless format.is_a?(Format)
|
235
|
+
format.format(self)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Formats this timestamp into a string according to {Format::DEFAULTS[0]}
|
239
|
+
#
|
240
|
+
# @return [String] the string representing the formatted timestamp
|
241
|
+
# @api public
|
242
|
+
def to_s
|
243
|
+
format(Format::DEFAULTS[0])
|
244
|
+
end
|
245
|
+
|
246
|
+
def to_hash(compact = false)
|
247
|
+
result = {}
|
248
|
+
n = nanoseconds
|
249
|
+
if compact
|
250
|
+
s = total_seconds
|
251
|
+
result[KEY_SECONDS] = negative? ? -s : s
|
252
|
+
result[KEY_NANOSECONDS] = negative? ? -n : n unless n == 0
|
253
|
+
else
|
254
|
+
add_unless_zero(result, KEY_DAYS, days)
|
255
|
+
add_unless_zero(result, KEY_HOURS, hours)
|
256
|
+
add_unless_zero(result, KEY_MINUTES, minutes)
|
257
|
+
add_unless_zero(result, KEY_SECONDS, seconds)
|
258
|
+
unless n == 0
|
259
|
+
add_unless_zero(result, KEY_NANOSECONDS, n % 1000)
|
260
|
+
n /= 1000
|
261
|
+
add_unless_zero(result, KEY_MICROSECONDS, n % 1000)
|
262
|
+
add_unless_zero(result, KEY_MILLISECONDS, n /= 1000)
|
263
|
+
end
|
264
|
+
result[KEY_NEGATIVE] = true if negative?
|
265
|
+
end
|
266
|
+
result
|
267
|
+
end
|
268
|
+
|
269
|
+
def add_unless_zero(result, key, value)
|
270
|
+
result[key] = value unless value == 0
|
271
|
+
end
|
272
|
+
private :add_unless_zero
|
273
|
+
|
274
|
+
# @api private
|
275
|
+
def total_days
|
276
|
+
total_nanoseconds / NSECS_PER_DAY
|
277
|
+
end
|
278
|
+
|
279
|
+
# @api private
|
280
|
+
def total_hours
|
281
|
+
total_nanoseconds / NSECS_PER_HOUR
|
282
|
+
end
|
283
|
+
|
284
|
+
# @api private
|
285
|
+
def total_minutes
|
286
|
+
total_nanoseconds / NSECS_PER_MIN
|
287
|
+
end
|
288
|
+
|
289
|
+
# @api private
|
290
|
+
def total_seconds
|
291
|
+
total_nanoseconds / NSECS_PER_SEC
|
292
|
+
end
|
293
|
+
|
294
|
+
# @api private
|
295
|
+
def total_milliseconds
|
296
|
+
total_nanoseconds / NSECS_PER_MSEC
|
297
|
+
end
|
298
|
+
|
299
|
+
# @api private
|
300
|
+
def total_microseconds
|
301
|
+
total_nanoseconds / NSECS_PER_USEC
|
302
|
+
end
|
303
|
+
|
304
|
+
# @api private
|
305
|
+
def total_nanoseconds
|
306
|
+
@nsecs.abs
|
307
|
+
end
|
308
|
+
|
309
|
+
# Represents a compiled Timestamp format. The format is used both when parsing a timestamp
|
310
|
+
# in string format and when producing a string from a timestamp instance.
|
311
|
+
#
|
312
|
+
class Format
|
313
|
+
# A segment is either a string that will be represented literally in the formatted timestamp
|
314
|
+
# or a value that corresponds to one of the possible format characters.
|
315
|
+
class Segment
|
316
|
+
def append_to(bld, ts)
|
317
|
+
raise NotImplementedError, "'#{self.class.name}' should implement #append_to"
|
318
|
+
end
|
319
|
+
|
320
|
+
def append_regexp(bld, ts)
|
321
|
+
raise NotImplementedError, "'#{self.class.name}' should implement #append_regexp"
|
322
|
+
end
|
323
|
+
|
324
|
+
def multiplier
|
325
|
+
raise NotImplementedError, "'#{self.class.name}' should implement #multiplier"
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
class LiteralSegment < Segment
|
330
|
+
def append_regexp(bld)
|
331
|
+
bld << "(#{Regexp.escape(@literal)})"
|
332
|
+
end
|
333
|
+
|
334
|
+
def initialize(literal)
|
335
|
+
@literal = literal
|
336
|
+
end
|
337
|
+
|
338
|
+
def append_to(bld, ts)
|
339
|
+
bld << @literal
|
340
|
+
end
|
341
|
+
|
342
|
+
def concat(codepoint)
|
343
|
+
@literal.concat(codepoint)
|
344
|
+
end
|
345
|
+
|
346
|
+
def nanoseconds
|
347
|
+
0
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
class ValueSegment < Segment
|
352
|
+
def initialize(padchar, width, default_width)
|
353
|
+
@use_total = false
|
354
|
+
@padchar = padchar
|
355
|
+
@width = width
|
356
|
+
@default_width = default_width
|
357
|
+
@format = create_format
|
358
|
+
end
|
359
|
+
|
360
|
+
def create_format
|
361
|
+
case @padchar
|
362
|
+
when nil
|
363
|
+
'%d'
|
364
|
+
when ' '
|
365
|
+
"%#{@width || @default_width}d"
|
366
|
+
else
|
367
|
+
"%#{@padchar}#{@width || @default_width}d"
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def append_regexp(bld)
|
372
|
+
if @width.nil?
|
373
|
+
case @padchar
|
374
|
+
when nil
|
375
|
+
bld << (use_total? ? '([0-9]+)' : "([0-9]{1,#{@default_width}})")
|
376
|
+
when '0'
|
377
|
+
bld << (use_total? ? '([0-9]+)' : "([0-9]{1,#{@default_width}})")
|
378
|
+
else
|
379
|
+
bld << (use_total? ? '\s*([0-9]+)' : "([0-9\\s]{1,#{@default_width}})")
|
380
|
+
end
|
381
|
+
else
|
382
|
+
case @padchar
|
383
|
+
when nil
|
384
|
+
bld << "([0-9]{1,#{@width}})"
|
385
|
+
when '0'
|
386
|
+
bld << "([0-9]{#{@width}})"
|
387
|
+
else
|
388
|
+
bld << "([0-9\\s]{#{@width}})"
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
def nanoseconds(group)
|
394
|
+
group.to_i * multiplier
|
395
|
+
end
|
396
|
+
|
397
|
+
def multiplier
|
398
|
+
0
|
399
|
+
end
|
400
|
+
|
401
|
+
def set_use_total
|
402
|
+
@use_total = true
|
403
|
+
end
|
404
|
+
|
405
|
+
def use_total?
|
406
|
+
@use_total
|
407
|
+
end
|
408
|
+
|
409
|
+
def append_value(bld, n)
|
410
|
+
bld << sprintf(@format, n)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
class DaySegment < ValueSegment
|
415
|
+
def initialize(padchar, width)
|
416
|
+
super(padchar, width, 1)
|
417
|
+
end
|
418
|
+
|
419
|
+
def multiplier
|
420
|
+
NSECS_PER_DAY
|
421
|
+
end
|
422
|
+
|
423
|
+
def append_to(bld, ts)
|
424
|
+
append_value(bld, ts.days)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
class HourSegment < ValueSegment
|
429
|
+
def initialize(padchar, width)
|
430
|
+
super(padchar, width, 2)
|
431
|
+
end
|
432
|
+
|
433
|
+
def multiplier
|
434
|
+
NSECS_PER_HOUR
|
435
|
+
end
|
436
|
+
|
437
|
+
def append_to(bld, ts)
|
438
|
+
append_value(bld, use_total? ? ts.total_hours : ts.hours)
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
class MinuteSegment < ValueSegment
|
443
|
+
def initialize(padchar, width)
|
444
|
+
super(padchar, width, 2)
|
445
|
+
end
|
446
|
+
|
447
|
+
def multiplier
|
448
|
+
NSECS_PER_MIN
|
449
|
+
end
|
450
|
+
|
451
|
+
def append_to(bld, ts)
|
452
|
+
append_value(bld, use_total? ? ts.total_minutes : ts.minutes)
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
class SecondSegment < ValueSegment
|
457
|
+
def initialize(padchar, width)
|
458
|
+
super(padchar, width, 2)
|
459
|
+
end
|
460
|
+
|
461
|
+
def multiplier
|
462
|
+
NSECS_PER_SEC
|
463
|
+
end
|
464
|
+
|
465
|
+
def append_to(bld, ts)
|
466
|
+
append_value(bld, use_total? ? ts.total_seconds : ts.seconds)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
# Class that assumes that leading zeroes are significant and that trailing zeroes are not and left justifies when formatting.
|
471
|
+
# Applicable after a decimal point, and hence to the %L and %N formats.
|
472
|
+
class FragmentSegment < ValueSegment
|
473
|
+
def nanoseconds(group)
|
474
|
+
# Using %L or %N to parse a string only makes sense when they are considered to be fractions. Using them
|
475
|
+
# as a total quantity would introduce ambiguities.
|
476
|
+
raise ArgumentError, 'Format specifiers %L and %N denotes fractions and must be used together with a specifier of higher magnitude' if use_total?
|
477
|
+
n = group.to_i
|
478
|
+
p = 9 - group.length
|
479
|
+
p <= 0 ? n : n * 10 ** p
|
480
|
+
end
|
481
|
+
|
482
|
+
def create_format
|
483
|
+
if @padchar.nil?
|
484
|
+
'%d'
|
485
|
+
else
|
486
|
+
"%-#{@width || @default_width}d"
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
def append_value(bld, n)
|
491
|
+
# Strip trailing zeroes when default format is used
|
492
|
+
n = n.to_s.sub(/\A([0-9]+?)0*\z/, '\1').to_i unless use_total? || @padchar == '0'
|
493
|
+
super(bld, n)
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
class MilliSecondSegment < FragmentSegment
|
498
|
+
def initialize(padchar, width)
|
499
|
+
super(padchar, width, 3)
|
500
|
+
end
|
501
|
+
|
502
|
+
def multiplier
|
503
|
+
NSECS_PER_MSEC
|
504
|
+
end
|
505
|
+
|
506
|
+
def append_to(bld, ts)
|
507
|
+
append_value(bld, use_total? ? ts.total_milliseconds : ts.milliseconds)
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
class NanoSecondSegment < FragmentSegment
|
512
|
+
def initialize(padchar, width)
|
513
|
+
super(padchar, width, 9)
|
514
|
+
end
|
515
|
+
|
516
|
+
def multiplier
|
517
|
+
width = @width || @default_width
|
518
|
+
if width < 9
|
519
|
+
10 ** (9 - width)
|
520
|
+
else
|
521
|
+
1
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
def append_to(bld, ts)
|
526
|
+
ns = ts.total_nanoseconds
|
527
|
+
width = @width || @default_width
|
528
|
+
if width < 9
|
529
|
+
# Truncate digits to the right, i.e. let %6N reflect microseconds
|
530
|
+
ns /= 10 ** (9 - width)
|
531
|
+
ns %= 10 ** width unless use_total?
|
532
|
+
else
|
533
|
+
ns %= NSECS_PER_SEC unless use_total?
|
534
|
+
end
|
535
|
+
append_value(bld, ns)
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
def initialize(format, segments)
|
540
|
+
@format = format.freeze
|
541
|
+
@segments = segments.freeze
|
542
|
+
end
|
543
|
+
|
544
|
+
def format(timespan)
|
545
|
+
bld = timespan.negative? ? '-' : ''
|
546
|
+
@segments.each { |segment| segment.append_to(bld, timespan) }
|
547
|
+
bld
|
548
|
+
end
|
549
|
+
|
550
|
+
def parse(timespan)
|
551
|
+
md = regexp.match(timespan)
|
552
|
+
raise ArgumentError, "Unable to parse '#{timespan}' using format '#{@format}'" if md.nil?
|
553
|
+
nanoseconds = 0
|
554
|
+
md.captures.each_with_index do |group, index|
|
555
|
+
segment = @segments[index]
|
556
|
+
next if segment.is_a?(LiteralSegment)
|
557
|
+
group.lstrip!
|
558
|
+
raise ArgumentError, "Unable to parse '#{timespan}' using format '#{@format}'" unless group =~ /\A[0-9]+\z/
|
559
|
+
nanoseconds += segment.nanoseconds(group)
|
560
|
+
end
|
561
|
+
Timespan.new(timespan.start_with?('-') ? -nanoseconds : nanoseconds)
|
562
|
+
end
|
563
|
+
|
564
|
+
def to_s
|
565
|
+
@format
|
566
|
+
end
|
567
|
+
|
568
|
+
private
|
569
|
+
|
570
|
+
def regexp
|
571
|
+
@regexp ||= build_regexp
|
572
|
+
end
|
573
|
+
|
574
|
+
def build_regexp
|
575
|
+
bld = '\A-?'
|
576
|
+
@segments.each { |segment| segment.append_regexp(bld) }
|
577
|
+
bld << '\z'
|
578
|
+
Regexp.new(bld)
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
# Parses a string into a Timestamp::Format instance
|
583
|
+
class FormatParser
|
584
|
+
def self.singleton
|
585
|
+
@singleton
|
586
|
+
end
|
587
|
+
|
588
|
+
def initialize
|
589
|
+
@formats = Hash.new { |hash, str| hash[str] = internal_parse(str) }
|
590
|
+
end
|
591
|
+
|
592
|
+
def parse_format(format)
|
593
|
+
@formats[format]
|
594
|
+
end
|
595
|
+
|
596
|
+
private
|
597
|
+
|
598
|
+
NSEC_MAX = 0
|
599
|
+
MSEC_MAX = 1
|
600
|
+
SEC_MAX = 2
|
601
|
+
MIN_MAX = 3
|
602
|
+
HOUR_MAX = 4
|
603
|
+
DAY_MAX = 5
|
604
|
+
|
605
|
+
SEGMENT_CLASS_BY_ORDINAL = [
|
606
|
+
Format::NanoSecondSegment, Format::MilliSecondSegment, Format::SecondSegment, Format::MinuteSegment, Format::HourSegment, Format::DaySegment
|
607
|
+
]
|
608
|
+
|
609
|
+
def bad_format_specifier(format, start, position)
|
610
|
+
"Bad format specifier '#{format[start,position-start]}' in '#{format}', at position #{position}"
|
611
|
+
end
|
612
|
+
|
613
|
+
def append_literal(bld, codepoint)
|
614
|
+
if bld.empty? || !bld.last.is_a?(Format::LiteralSegment)
|
615
|
+
bld << Format::LiteralSegment.new(''.concat(codepoint))
|
616
|
+
else
|
617
|
+
bld.last.concat(codepoint)
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
# States used by the #internal_parser function
|
622
|
+
STATE_LITERAL = 0 # expects literal or '%'
|
623
|
+
STATE_PAD = 1 # expects pad, width, or format character
|
624
|
+
STATE_WIDTH = 2 # expects width, or format character
|
625
|
+
|
626
|
+
def internal_parse(str)
|
627
|
+
bld = []
|
628
|
+
raise ArgumentError, 'Format must be a String' unless str.is_a?(String)
|
629
|
+
highest = -1
|
630
|
+
state = STATE_LITERAL
|
631
|
+
padchar = '0'
|
632
|
+
width = nil
|
633
|
+
position = -1
|
634
|
+
fstart = 0
|
635
|
+
|
636
|
+
str.codepoints do |codepoint|
|
637
|
+
position += 1
|
638
|
+
if state == STATE_LITERAL
|
639
|
+
if codepoint == 0x25 # '%'
|
640
|
+
state = STATE_PAD
|
641
|
+
fstart = position
|
642
|
+
padchar = '0'
|
643
|
+
width = nil
|
644
|
+
else
|
645
|
+
append_literal(bld, codepoint)
|
646
|
+
end
|
647
|
+
next
|
648
|
+
end
|
649
|
+
|
650
|
+
case codepoint
|
651
|
+
when 0x25 # '%'
|
652
|
+
append_literal(bld, codepoint)
|
653
|
+
state = STATE_LITERAL
|
654
|
+
when 0x2D # '-'
|
655
|
+
raise ArgumentError, bad_format_specifier(str, fstart, position) unless state == STATE_PAD
|
656
|
+
padchar = nil
|
657
|
+
state = STATE_WIDTH
|
658
|
+
when 0x5F # '_'
|
659
|
+
raise ArgumentError, bad_format_specifier(str, fstart, position) unless state == STATE_PAD
|
660
|
+
padchar = ' '
|
661
|
+
state = STATE_WIDTH
|
662
|
+
when 0x44 # 'D'
|
663
|
+
highest = DAY_MAX
|
664
|
+
bld << Format::DaySegment.new(padchar, width)
|
665
|
+
state = STATE_LITERAL
|
666
|
+
when 0x48 # 'H'
|
667
|
+
highest = HOUR_MAX unless highest > HOUR_MAX
|
668
|
+
bld << Format::HourSegment.new(padchar, width)
|
669
|
+
state = STATE_LITERAL
|
670
|
+
when 0x4D # 'M'
|
671
|
+
highest = MIN_MAX unless highest > MIN_MAX
|
672
|
+
bld << Format::MinuteSegment.new(padchar, width)
|
673
|
+
state = STATE_LITERAL
|
674
|
+
when 0x53 # 'S'
|
675
|
+
highest = SEC_MAX unless highest > SEC_MAX
|
676
|
+
bld << Format::SecondSegment.new(padchar, width)
|
677
|
+
state = STATE_LITERAL
|
678
|
+
when 0x4C # 'L'
|
679
|
+
highest = MSEC_MAX unless highest > MSEC_MAX
|
680
|
+
bld << Format::MilliSecondSegment.new(padchar, width)
|
681
|
+
state = STATE_LITERAL
|
682
|
+
when 0x4E # 'N'
|
683
|
+
highest = NSEC_MAX unless highest > NSEC_MAX
|
684
|
+
bld << Format::NanoSecondSegment.new(padchar, width)
|
685
|
+
state = STATE_LITERAL
|
686
|
+
else # only digits allowed at this point
|
687
|
+
raise ArgumentError, bad_format_specifier(str, fstart, position) unless codepoint >= 0x30 && codepoint <= 0x39
|
688
|
+
if state == STATE_PAD && codepoint == 0x30
|
689
|
+
padchar = '0'
|
690
|
+
else
|
691
|
+
n = codepoint - 0x30
|
692
|
+
if width.nil?
|
693
|
+
width = n
|
694
|
+
else
|
695
|
+
width = width * 10 + n
|
696
|
+
end
|
697
|
+
end
|
698
|
+
state = STATE_WIDTH
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
raise ArgumentError, bad_format_specifier(str, fstart, position) unless state == STATE_LITERAL
|
703
|
+
unless highest == -1
|
704
|
+
hc = SEGMENT_CLASS_BY_ORDINAL[highest]
|
705
|
+
bld.find { |s| s.instance_of?(hc) }.set_use_total
|
706
|
+
end
|
707
|
+
Format.new(str, bld)
|
708
|
+
end
|
709
|
+
|
710
|
+
@singleton = FormatParser.new
|
711
|
+
end
|
712
|
+
|
713
|
+
class Format
|
714
|
+
DEFAULTS = ['%D-%H:%M:%S.%-N', '%H:%M:%S.%-N', '%M:%S.%-N', '%S.%-N', '%D-%H:%M:%S', '%H:%M:%S', '%D-%H:%M', '%S'].map { |str| FormatParser.singleton.parse_format(str) }
|
715
|
+
end
|
716
|
+
end
|
717
|
+
end
|
718
|
+
end
|