date_holidays-reader 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
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