date_holidays-reader 0.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.nvmrc +1 -0
- data/.rspec +3 -0
- data/.rubocop.yml +27 -0
- data/.ruby-version +1 -0
- data/.travis.yml +17 -0
- data/CHANGELOG.md +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Dockerfile +19 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +105 -0
- data/Guardfile +44 -0
- data/LICENSE +17 -0
- data/README.md +176 -0
- data/Rakefile +18 -0
- data/bin/add-copyright-header.pl +16 -0
- data/bin/console +21 -0
- data/bin/date-holidays-version.js +21 -0
- data/bin/holidays-to-json.js +70 -0
- data/bin/setup +17 -0
- data/date-holiday-reader.gemspec +49 -0
- data/lib/date_holidays/reader.rb +26 -0
- data/lib/date_holidays/reader/config.rb +54 -0
- data/lib/date_holidays/reader/holiday.rb +78 -0
- data/lib/date_holidays/reader/js_bridge.rb +75 -0
- data/lib/date_holidays/reader/locale.rb +109 -0
- data/lib/date_holidays/reader/version.rb +67 -0
- data/package.json +12 -0
- data/yarn.lock +1686 -0
- metadata +245 -0
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
task default: :spec
|
9
|
+
|
10
|
+
CLOBBER.include(%w[pkg node_bin])
|
11
|
+
|
12
|
+
desc 'Compile the Node dependencies'
|
13
|
+
task :node_compile do
|
14
|
+
sh 'yarn run pkg bin/holidays-to-json.js --out-path=node_bin --targets=macos-x64,linux-x64'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Add node_compile as a dependency to the existing build task defined by bundler:
|
18
|
+
task build: :node_compile
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env perl -i -p
|
2
|
+
|
3
|
+
# Adds copyright headers to files passed in.
|
4
|
+
# Example:
|
5
|
+
# find . -name '*.rb' -exec bin/add-copyright-header.pl {} \;
|
6
|
+
|
7
|
+
$header = <<'END_HEADER';
|
8
|
+
#
|
9
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
10
|
+
#
|
11
|
+
# This source code is licensed under the MIT license found in the
|
12
|
+
# LICENSE file in the root directory of this source tree.
|
13
|
+
#
|
14
|
+
END_HEADER
|
15
|
+
|
16
|
+
s/(# frozen_string_literal: true\n)/$1\n$header/
|
data/bin/console
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "bundler/setup"
|
11
|
+
require "date_holidays/reader"
|
12
|
+
|
13
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
14
|
+
# with your gem easier. You can also use a different console, if you like.
|
15
|
+
|
16
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
17
|
+
# require "pry"
|
18
|
+
# Pry.start
|
19
|
+
|
20
|
+
require "irb"
|
21
|
+
IRB.start(__FILE__)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
/*
|
4
|
+
Copyright(c) 2019 - present, Blue Marble Payroll, LLC
|
5
|
+
|
6
|
+
This source code is licensed under the MIT license found in the
|
7
|
+
LICENSE file in the root directory of this source tree.
|
8
|
+
*/
|
9
|
+
|
10
|
+
'use strict'
|
11
|
+
|
12
|
+
const path = require('path');
|
13
|
+
const fs = require('fs');
|
14
|
+
|
15
|
+
const dateHolidaysIndexJsPath = require.resolve('date-holidays');
|
16
|
+
|
17
|
+
const dateHolidaysPackageJsonPath = path.join(
|
18
|
+
path.dirname(dateHolidaysIndexJsPath), '..', 'package.json'
|
19
|
+
);
|
20
|
+
|
21
|
+
console.log(JSON.parse(fs.readFileSync(dateHolidaysPackageJsonPath)).version);
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
/*
|
4
|
+
Copyright(c) 2019 - present, Blue Marble Payroll, LLC
|
5
|
+
|
6
|
+
This source code is licensed under the MIT license found in the
|
7
|
+
LICENSE file in the root directory of this source tree.
|
8
|
+
*/
|
9
|
+
|
10
|
+
'use strict'
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Adapted from sample.js (https://github.com/commenthol/date-holidays/blob/master/test/sample.js).
|
14
|
+
* holidays-to-json.js sub_command [country.state.region] [year] [--lang en] [--state ca]
|
15
|
+
* e.g.
|
16
|
+
* holidays-to-json.js holidays at.b 2015
|
17
|
+
*/
|
18
|
+
var Holidays = require('date-holidays');
|
19
|
+
|
20
|
+
const COMMANDS = Object.freeze({
|
21
|
+
holidays: (hd, opts) => hd.getHolidays(opts.year),
|
22
|
+
countries: (hd, _) => hd.getCountries(),
|
23
|
+
// Note that the language isn't working here. This appears to be a bug in the node module.
|
24
|
+
states: (hd, opts) => hd.getStates(opts.country, opts.languages.first),
|
25
|
+
regions: (hd, opts) => hd.getRegions(opts.country, opts.state, opts.languages.first),
|
26
|
+
languages: (hd, _) => hd.getLanguages(),
|
27
|
+
time_zones: (hd, _) => hd.getTimezones(),
|
28
|
+
});
|
29
|
+
const DEFAULT_LANGUAGE = 'en';
|
30
|
+
|
31
|
+
function extractData(cmd, hd, opts) {
|
32
|
+
const extractor = COMMANDS[cmd]
|
33
|
+
let result = {};
|
34
|
+
|
35
|
+
if (extractor) {
|
36
|
+
result = extractor(hd, opts);
|
37
|
+
} else {
|
38
|
+
console.error("Uknown sub-command: " + cmd);
|
39
|
+
console.error("Valid sub-commands are: " + Object.keys(COMMANDS).join(', '));
|
40
|
+
process.exit(1);
|
41
|
+
}
|
42
|
+
|
43
|
+
// Always return the empty object so that it converts nicely to JSON.
|
44
|
+
return result || {};
|
45
|
+
}
|
46
|
+
|
47
|
+
if (module === require.main) {
|
48
|
+
const opts = {};
|
49
|
+
const args = process.argv.slice(2);
|
50
|
+
const cmd = args.shift();
|
51
|
+
var arg;
|
52
|
+
|
53
|
+
while ((arg = args.shift())) {
|
54
|
+
if (arg === '--lang') {
|
55
|
+
opts.languages = args.shift();
|
56
|
+
} else if (arg === '--state') {
|
57
|
+
opts.state = args.shift();
|
58
|
+
} else if (/^\d{4}$/.test(arg)) {
|
59
|
+
opts.year = arg;
|
60
|
+
} else if (/^[a-zA-Z]{2}/.test(arg)) {
|
61
|
+
opts.country = arg;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
opts.year = opts.year || (new Date()).getFullYear();
|
66
|
+
opts.languages = opts.languages || [DEFAULT_LANGUAGE];
|
67
|
+
|
68
|
+
var hd = new Holidays(opts.country, { languages: opts.languages, state: opts.state } );
|
69
|
+
console.log(JSON.stringify(extractData(cmd, hd, opts)));
|
70
|
+
}
|
data/bin/setup
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
set -euo pipefail
|
10
|
+
IFS=$'\n\t'
|
11
|
+
set -vx
|
12
|
+
|
13
|
+
bundle install
|
14
|
+
yarn
|
15
|
+
rake build
|
16
|
+
|
17
|
+
# Do any other automated setup that you need to do here
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'date_holidays/reader/version'
|
6
|
+
|
7
|
+
# rubocop:disable Metrics/BlockLength
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'date_holidays-reader'
|
10
|
+
spec.version = DateHolidays::Reader::VERSION
|
11
|
+
spec.authors = ['Ryan Gerry']
|
12
|
+
spec.email = ['rgerry@bluemarblepayroll.com']
|
13
|
+
|
14
|
+
spec.summary = 'A read only Ruby wrapper for the date-holidays Node module'
|
15
|
+
spec.description = <<~DESCRIPTION
|
16
|
+
This provides a read only interace over the data provided by the
|
17
|
+
date-holidays Node module available at https://github.com/commenthol/date-holidays .'
|
18
|
+
DESCRIPTION
|
19
|
+
spec.homepage = 'http://www.github.com/bluemarblepayroll/date_holidays-reader/'
|
20
|
+
spec.metadata['source_code_uri'] = 'https://github.com/bluemarblepayroll/date_holidays-reader'
|
21
|
+
spec.metadata['changelog_uri'] = 'https://github.com/bluemarblepayroll/date_holidays-reader/blob/master/CHANGELOG.md'
|
22
|
+
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
26
|
+
git_files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
27
|
+
node_bin = Dir.glob('node_bin/*')
|
28
|
+
|
29
|
+
git_files + node_bin
|
30
|
+
end
|
31
|
+
spec.bindir = 'exe'
|
32
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ['lib']
|
34
|
+
|
35
|
+
spec.add_dependency 'acts_as_hashable', '~> 1'
|
36
|
+
spec.add_dependency 'caution'
|
37
|
+
spec.add_dependency 'os', '~> 1'
|
38
|
+
|
39
|
+
spec.add_development_dependency 'bundler', '~> 1.17'
|
40
|
+
spec.add_development_dependency 'guard'
|
41
|
+
spec.add_development_dependency 'guard-rspec'
|
42
|
+
spec.add_development_dependency 'pry'
|
43
|
+
spec.add_development_dependency 'pry-byebug'
|
44
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
45
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
46
|
+
spec.add_development_dependency 'rubocop'
|
47
|
+
spec.add_development_dependency 'terminal-notifier-guard'
|
48
|
+
end
|
49
|
+
# rubocop:enable Metrics/BlockLength
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'acts_as_hashable'
|
11
|
+
require 'caution'
|
12
|
+
require 'json'
|
13
|
+
require 'os'
|
14
|
+
|
15
|
+
require 'date_holidays/reader/config'
|
16
|
+
require 'date_holidays/reader/holiday'
|
17
|
+
require 'date_holidays/reader/js_bridge'
|
18
|
+
require 'date_holidays/reader/locale'
|
19
|
+
require 'date_holidays/reader/version'
|
20
|
+
|
21
|
+
module DateHolidays
|
22
|
+
# Defines the outermost module for the gem.
|
23
|
+
module Reader
|
24
|
+
# Your code goes here...
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
module DateHolidays
|
11
|
+
module Reader
|
12
|
+
# Tells the gem how to interact with Node and provides a list of countries.
|
13
|
+
# See the configuration section of the Readme for more inforamtion.
|
14
|
+
class Config
|
15
|
+
SUPPORTED_CPU_BITS = 64
|
16
|
+
private_constant :SUPPORTED_CPU_BITS
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_reader :node_path
|
20
|
+
attr_writer :default
|
21
|
+
|
22
|
+
def node_path=(path)
|
23
|
+
# Clear out the cached config when the node path changes:
|
24
|
+
@default = nil
|
25
|
+
@node_path = path
|
26
|
+
end
|
27
|
+
|
28
|
+
def default
|
29
|
+
@default ||= new(node_path: node_path)
|
30
|
+
end
|
31
|
+
|
32
|
+
def countries
|
33
|
+
JsBridge.new.extract(:countries)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :node_path
|
38
|
+
|
39
|
+
def initialize(node_path: nil)
|
40
|
+
@node_path = node_path
|
41
|
+
|
42
|
+
freeze
|
43
|
+
end
|
44
|
+
|
45
|
+
def native_mac?
|
46
|
+
OS.osx? && OS.bits == SUPPORTED_CPU_BITS
|
47
|
+
end
|
48
|
+
|
49
|
+
def native_linux?
|
50
|
+
OS.linux? && OS.bits == SUPPORTED_CPU_BITS
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
# Use time from the standard library (instead of core) which has .strptime:
|
11
|
+
require 'time'
|
12
|
+
|
13
|
+
module DateHolidays
|
14
|
+
module Reader
|
15
|
+
# A holiday which includes a date, start and end times, name, and type.
|
16
|
+
# Based on https://github.com/commenthol/date-holidays#holiday-object .
|
17
|
+
#
|
18
|
+
# The date is represented as a Ruby Date instance as it is the
|
19
|
+
# holiday start date in the local time zone.
|
20
|
+
#
|
21
|
+
# Start and end times are represented as Time instances in UTC. Note that
|
22
|
+
# New Year's day in the US has a start time of January 1st at 5 AM UTC as
|
23
|
+
# Eastern Standard Time is five hours after UTC.
|
24
|
+
class Holiday
|
25
|
+
acts_as_hashable
|
26
|
+
|
27
|
+
attr_reader :date, :start_time, :end_time, :name, :type, :note
|
28
|
+
|
29
|
+
# rubocop:disable Metrics/ParameterLists
|
30
|
+
# This cop defaults to five parameters which seems a little low for
|
31
|
+
# keyword arguments. This is a value object which gets frozen after
|
32
|
+
# initialization so I'd rather pass in everything as needed right away.
|
33
|
+
def initialize(date:, start_time:, end_time:, name:, type:, substitute: false, note: nil)
|
34
|
+
# rubocop:enable Metrics/ParameterLists
|
35
|
+
@date = date.is_a?(Date) ? date : Date.strptime(date, '%Y-%m-%d')
|
36
|
+
@start_time = parse_time(start_time)
|
37
|
+
@end_time = parse_time(end_time)
|
38
|
+
@name = name
|
39
|
+
@type = type.to_sym
|
40
|
+
@substitute = substitute
|
41
|
+
@note = note
|
42
|
+
|
43
|
+
freeze
|
44
|
+
end
|
45
|
+
|
46
|
+
def substitute?
|
47
|
+
@substitute
|
48
|
+
end
|
49
|
+
|
50
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
51
|
+
# I could cut down on those cops by iterating over instance variable and
|
52
|
+
# using meta programming. However, that would obscure intent.
|
53
|
+
def ==(other)
|
54
|
+
other.is_a?(self.class) &&
|
55
|
+
other.date == date &&
|
56
|
+
other.start_time == start_time &&
|
57
|
+
other.end_time == end_time &&
|
58
|
+
other.name == name &&
|
59
|
+
other.type == type &&
|
60
|
+
other.substitute? == substitute? &&
|
61
|
+
other.note == note
|
62
|
+
end
|
63
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def parse_time(time)
|
68
|
+
# Example time string: "2018-01-01T05:00:00.000Z"
|
69
|
+
time.is_a?(Time) ? time : Time.xmlschema(time)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# For reference:
|
76
|
+
# Core Time: https://ruby-doc.org/core-2.3.6/Time.html
|
77
|
+
# Stdlib Time: https://ruby-doc.org/stdlib-2.3.8/libdoc/time/rdoc/Time.html
|
78
|
+
# Stdlib Date: http://ruby-doc.org/stdlib-2.3.8/libdoc/date/rdoc/Date.html
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
module DateHolidays
|
11
|
+
module Reader
|
12
|
+
# A communication bridge to the JavaScript process which houses the date-holidays node module.
|
13
|
+
class JsBridge
|
14
|
+
BIN_PATH = File.expand_path('../../../bin', __dir__).freeze
|
15
|
+
|
16
|
+
JS_PROGRAM_PATH = File.expand_path(File.join(BIN_PATH, '/holidays-to-json.js')).freeze
|
17
|
+
NODE_BIN_PATH = File.expand_path('../../../node_bin', __dir__).freeze
|
18
|
+
private_constant :JS_PROGRAM_PATH, :NODE_BIN_PATH
|
19
|
+
|
20
|
+
attr_reader :config, :debug
|
21
|
+
|
22
|
+
# TODO: initialize with a configuration object for how to run the command
|
23
|
+
def initialize(config = Config.default, debug: false)
|
24
|
+
@config = config
|
25
|
+
@debug = debug
|
26
|
+
|
27
|
+
freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
def extract(sub_cmd, *args)
|
31
|
+
JSON.parse(get_output(holidays_to_json_command + [sub_cmd, *args]))
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_output(args)
|
35
|
+
args = Array(args)
|
36
|
+
cmd_tokens_as_strings = args.map(&:to_s)
|
37
|
+
output = nil
|
38
|
+
|
39
|
+
print_command(cmd_tokens_as_strings) if debug
|
40
|
+
|
41
|
+
IO.popen(cmd_tokens_as_strings, err: %i[child out]) { |cmd_io| output = cmd_io.read }
|
42
|
+
output
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Returns an array of strings containing the tokens to execute the
|
48
|
+
# date-holidays wrapper depending on configuration.
|
49
|
+
def holidays_to_json_command
|
50
|
+
if config.node_path
|
51
|
+
[config.node_path, JS_PROGRAM_PATH]
|
52
|
+
elsif pre_compiled_program
|
53
|
+
[File.join(NODE_BIN_PATH, pre_compiled_program)]
|
54
|
+
else
|
55
|
+
# Fallback: a node path has not been configured and there is no
|
56
|
+
# pre-compiled program for this OS so fallback to the shebang line in
|
57
|
+
# the JS file.
|
58
|
+
[JS_PROGRAM_PATH]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def pre_compiled_program
|
63
|
+
if config.native_mac?
|
64
|
+
'holidays-to-json-macos'
|
65
|
+
elsif config.native_linux?
|
66
|
+
'holidays-to-json-linux'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def output_command(cmd_args)
|
71
|
+
puts "#{self.class}: about to invoke: '#{cmd_args.join(' ')}'"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|