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.
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