proforma-extended-evaluator 1.0.0.pre.alpha → 1.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39f0512316231d5d6072f4a26afa88b956d2ae6f1a4b8cf2aa9d45fed2beaba0
4
- data.tar.gz: f960a2c8956402fd065466c06468d8e8a3b8103a2f5274c72d35c7f8cbf62eec
3
+ metadata.gz: 3f978fa2a4a04564213b30c11f6b1353734dd8df889c047b989a385857aade8e
4
+ data.tar.gz: 75f683c4fb9689f6b081aa2b3f1d634cf3111d3c22c23d26481d82da8b6175e5
5
5
  SHA512:
6
- metadata.gz: 7de610f73e925ab605818eb5db4472d2aa5c93f95772c8a4f90040301c6ba80929734a5196d19a6766991c3fdf42e78d0e991d4304fccb3d9f19705f5c820f9b
7
- data.tar.gz: 98ad38935c497f6c3742d944a5084c6161ea8033a52095ea68d45a491553da3deba260da85b8b306fc8856fe085734c4c60b4b9ae27acf66b01c0fbbbab754d7
6
+ metadata.gz: 5da22925132f972ebf226007b8b0b191336db4fc6a1e91d7b1ecb26401eeb5baa9f02c97abc3c87ce4bd4622611a191f826b28295184c1e870fa2bbed2e9be03
7
+ data.tar.gz: f4e482ce9399c495a1ffd08bb5f81c000fb0ba2256c5d370de1ddcbae9fbc9c7b7feb37e056cd610187a25f2bce76db4ec1bdcadad6ff230205ffa93939b41b7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 1.0.0 (April 24th, 2019)
2
+
3
+ Publishing first release.
4
+
1
5
  # 1.0.0-alpha (April 19th, 2019)
2
6
 
3
7
  Publishing first candidate of initial release.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- proforma-extended-evaluator (1.0.0.pre.alpha)
4
+ proforma-extended-evaluator (1.0.0)
5
5
  stringento (~> 2)
6
6
 
7
7
  GEM
@@ -46,7 +46,7 @@ GEM
46
46
  parser (2.6.0.0)
47
47
  ast (~> 2.4.0)
48
48
  powerpack (0.1.2)
49
- proforma (1.0.0.pre.alpha)
49
+ proforma (1.0.0)
50
50
  acts_as_hashable (~> 1)
51
51
  pry (0.12.2)
52
52
  coderay (~> 1.1.0)
@@ -97,7 +97,7 @@ PLATFORMS
97
97
 
98
98
  DEPENDENCIES
99
99
  guard-rspec (~> 4.7)
100
- proforma (>= 1.0.0.pre.alpha)
100
+ proforma (~> 1)
101
101
  proforma-extended-evaluator!
102
102
  pry (~> 0)
103
103
  rspec (~> 3.8)
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/proforma-extended-evaluator.svg)](https://badge.fury.io/rb/proforma-extended-evaluator) [![Build Status](https://travis-ci.org/bluemarblepayroll/proforma-extended-evaluator.svg?branch=master)](https://travis-ci.org/bluemarblepayroll/proforma-extended-evaluator) [![Maintainability](https://api.codeclimate.com/v1/badges/79e66b596906f633bc95/maintainability)](https://codeclimate.com/github/bluemarblepayroll/proforma-extended-evaluator/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/79e66b596906f633bc95/test_coverage)](https://codeclimate.com/github/bluemarblepayroll/proforma-extended-evaluator/test_coverage) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
- The core Proforma library intentionally ships with a very weak evaluator. Custom text templating and value resolution is not part of the core library's domain. This library fills that void. The goals of this library are to provide:
5
+ The core [Proforma](https://github.com/bluemarblepayroll/proforma) library intentionally ships with a very weak evaluator. Custom text templating and value resolution is not part of the core library's domain. This library fills that void. The goals of this library are to provide:
6
6
 
7
7
  1. Nested value resolution using dot-notation: `demographics.contact.first_name`
8
8
  2. Indifferent object types for value resolution: Hash, OpenStruct, any Object subclass, etc.
@@ -34,9 +34,9 @@ bundle add proforma-extended-evaluator
34
34
 
35
35
  ### Connecting to Proforma Rendering Pipeline
36
36
 
37
- To use this plugin within Proforma:
37
+ To use this plugin within [Proforma](https://github.com/bluemarblepayroll/proforma):
38
38
 
39
- 1. Install Proforma
39
+ 1. Install [Proforma](https://github.com/bluemarblepayroll/proforma)
40
40
  2. Install this library
41
41
  3. Require both libraries
42
42
  4. Pass in an instance of Proforma::ExtendedEvaluator into the Proforma#render method
@@ -8,6 +8,7 @@
8
8
  #
9
9
 
10
10
  require 'bigdecimal'
11
+ require 'forwardable'
11
12
  require 'stringento'
12
13
 
13
14
  require_relative 'extended_evaluator/formatter'
@@ -13,47 +13,51 @@ module Proforma
13
13
  # plugged into Stringento to provide formatting for data types, such as: strings, dates,
14
14
  # currency, numbers, etc.
15
15
  class Formatter < Stringento::Formatter
16
+ extend Forwardable
17
+
16
18
  DEFAULTS = {
17
19
  currency_code: 'USD',
18
20
  currency_round: 2,
19
21
  currency_symbol: '$',
20
22
  date_format: '%m/%d/%Y',
23
+ decimal_separator: '.',
24
+ iso_date_format: '%Y-%m-%d',
21
25
  mask_char: 'X',
22
26
  false_value: 'No',
23
27
  null_value: 'Unknown',
24
- true_value: 'Yes'
28
+ nullish_regex: /\A(nil|null)\z/i.freeze,
29
+ thousands_regex: /[0-9](?=(?:[0-9]{3})+(?![0-9]))/.freeze,
30
+ thousands_separator: ',',
31
+ true_value: 'Yes',
32
+ truthy_regex: /\A(true|t|yes|y|1)\z/i.freeze
25
33
  }.freeze
26
34
 
27
- ISO_DATE_FORMAT = '%Y-%m-%d'
28
- NULLISH = /(nil|null)$/i.freeze
29
- THOUSANDS_WITH_DECIMAL = /(\d)(?=\d{3}+\.)/.freeze
30
- THOUSANDS_WITHOUT_DECIMAL = /(\d)(?=\d{3}+$)/.freeze
31
- TRUTHY = /(true|t|yes|y|1)$/i.freeze
32
-
33
- attr_reader :currency_code,
34
- :currency_round,
35
- :currency_symbol,
36
- :date_format,
37
- :false_value,
38
- :mask_char,
39
- :null_value,
40
- :true_value
35
+ attr_reader :options
36
+
37
+ def_delegators :options,
38
+ :currency_code,
39
+ :currency_round,
40
+ :currency_symbol,
41
+ :date_format,
42
+ :decimal_separator,
43
+ :iso_date_format,
44
+ :false_value,
45
+ :mask_char,
46
+ :null_value,
47
+ :nullish_regex,
48
+ :thousands_regex,
49
+ :thousands_separator,
50
+ :truthy_regex,
51
+ :true_value
41
52
 
42
53
  def initialize(opts = {})
43
- opts = DEFAULTS.merge(opts)
44
-
45
- @currency_code = opts[:currency_code]
46
- @currency_round = opts[:currency_round]
47
- @currency_symbol = opts[:currency_symbol]
48
- @date_format = opts[:date_format]
49
- @false_value = opts[:false_value]
50
- @mask_char = opts[:mask_char]
51
- @null_value = opts[:null_value]
52
- @true_value = opts[:true_value]
54
+ @options = OpenStruct.new(DEFAULTS.merge(opts))
53
55
  end
54
56
 
55
- def left_mask_formatter(value, arg)
56
- keep_last = arg.to_s.empty? ? 4 : arg.to_s.to_i
57
+ def left_mask_formatter(value, keep_last)
58
+ keep_last = keep_last.to_s.empty? ? 4 : keep_last.to_s.to_i
59
+
60
+ raise ArgumentError, "keep_last cannot be negative (#{keep_last})" if keep_last.negative?
57
61
 
58
62
  string_value = value.to_s
59
63
 
@@ -66,7 +70,7 @@ module Proforma
66
70
  def date_formatter(value, _arg)
67
71
  return '' if null_or_empty?(value)
68
72
 
69
- date = Date.strptime(value.to_s, ISO_DATE_FORMAT)
73
+ date = Date.strptime(value.to_s, iso_date_format)
70
74
 
71
75
  date.strftime(date_format)
72
76
  end
@@ -82,16 +86,16 @@ module Proforma
82
86
  "#{prefix}#{formatted_value}#{suffix}"
83
87
  end
84
88
 
85
- def number_formatter(value, arg)
86
- decimal_places = arg.to_s.empty? ? 6 : arg.to_s.to_i
87
-
88
- regex = decimal_places.positive? ? THOUSANDS_WITH_DECIMAL : THOUSANDS_WITHOUT_DECIMAL
89
+ def number_formatter(value, decimal_places)
90
+ decimal_places = decimal_places.to_s.empty? ? 6 : decimal_places.to_s.to_i
89
91
 
90
- format("%0.#{decimal_places}f", value || 0).gsub(regex, '\1,')
92
+ format("%0.#{decimal_places}f", value || 0)
93
+ .gsub(thousands_regex, "\\0#{thousands_separator}")
94
+ .gsub('.', decimal_separator)
91
95
  end
92
96
 
93
- def boolean_formatter(value, arg)
94
- nullable = arg.to_s == 'nullable'
97
+ def boolean_formatter(value, nullable)
98
+ nullable = nullable.to_s == 'nullable'
95
99
 
96
100
  if nullable && nully?(value)
97
101
  null_value
@@ -117,11 +121,11 @@ module Proforma
117
121
 
118
122
  # rubocop:disable Style/DoubleNegation
119
123
  def nully?(val)
120
- null_or_empty?(val) || !!(val.to_s =~ NULLISH)
124
+ null_or_empty?(val) || !!(val.to_s =~ nullish_regex)
121
125
  end
122
126
 
123
127
  def truthy?(val)
124
- !!(val.to_s =~ TRUTHY)
128
+ !!(val.to_s =~ truthy_regex)
125
129
  end
126
130
  # rubocop:enable Style/DoubleNegation
127
131
  end
@@ -11,14 +11,26 @@ module Proforma
11
11
  class ExtendedEvaluator
12
12
  # This class is also meant to be plugged into Stringento to provide value resolution.
13
13
  class Resolver
14
- DOT_NOTATION_SEPARATOR = '.'
14
+ DEFAULT_SEPARATOR = '.'
15
+
16
+ attr_reader :separator
17
+
18
+ def initialize(separator: DEFAULT_SEPARATOR)
19
+ @separator = separator.to_s
20
+ end
15
21
 
16
22
  def resolve(value, input)
17
- traverse(input, value.to_s.split(DOT_NOTATION_SEPARATOR))
23
+ traverse(input, key_path(value))
18
24
  end
19
25
 
20
26
  private
21
27
 
28
+ def key_path(value)
29
+ return Array(value.to_s) if separator.empty?
30
+
31
+ value.to_s.split(separator)
32
+ end
33
+
22
34
  def traverse(object, through)
23
35
  pointer = object
24
36
 
@@ -35,7 +47,7 @@ module Proforma
35
47
  if object.is_a?(Hash)
36
48
  indifferent_hash_get(object, key)
37
49
  elsif object.respond_to?(key)
38
- object.send(key)
50
+ object.public_send(key)
39
51
  end
40
52
  end
41
53
 
@@ -9,6 +9,6 @@
9
9
 
10
10
  module Proforma
11
11
  class ExtendedEvaluator
12
- VERSION = '1.0.0-alpha'
12
+ VERSION = '1.0.0'
13
13
  end
14
14
  end
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_dependency('stringento', '~>2')
26
26
 
27
27
  s.add_development_dependency('guard-rspec', '~>4.7')
28
- s.add_development_dependency('proforma', '>=1.0.0-alpha')
28
+ s.add_development_dependency('proforma', '~>1')
29
29
  s.add_development_dependency('pry', '~>0')
30
30
  s.add_development_dependency('rspec', '~> 3.8')
31
31
  s.add_development_dependency('rubocop', '~>0.63.1')
@@ -10,6 +10,18 @@
10
10
  require 'spec_helper'
11
11
 
12
12
  describe Proforma::ExtendedEvaluator::Formatter do
13
+ let(:usa_formatter) { described_class.new }
14
+
15
+ let(:france_formatter) do
16
+ described_class.new(
17
+ currency_code: '€',
18
+ currency_round: 2,
19
+ currency_symbol: '',
20
+ decimal_separator: ',',
21
+ thousands_separator: ' '
22
+ )
23
+ end
24
+
13
25
  describe '#left_mask_formatter' do
14
26
  specify 'returns empty string if value is null' do
15
27
  expect(subject.left_mask_formatter(nil, '')).to eq('')
@@ -43,6 +55,10 @@ describe Proforma::ExtendedEvaluator::Formatter do
43
55
  expect(subject.left_mask_formatter('abcde', arg)).to eq('XXXde')
44
56
  expect(subject.left_mask_formatter('abcdef', arg)).to eq('XXXXef')
45
57
  end
58
+
59
+ specify 'raises ArgumentError for negative arg' do
60
+ expect { subject.left_mask_formatter(nil, -1) }.to raise_error(ArgumentError)
61
+ end
46
62
  end
47
63
  end
48
64
 
@@ -68,51 +84,63 @@ describe Proforma::ExtendedEvaluator::Formatter do
68
84
  end
69
85
  end
70
86
 
71
- describe '#currency_formatter' do
72
- subject do
73
- described_class.new(
74
- currency_code: 'USD',
75
- currency_round: 2,
76
- currency_symbol: '$'
77
- )
78
- end
87
+ describe '#number_formatter' do
88
+ context 'localized for USA (default)' do
89
+ subject { usa_formatter }
79
90
 
80
- let(:arg) { '' }
91
+ let(:arg) { '3' }
81
92
 
82
- specify 'returns empty string if value is null' do
83
- expect(subject.currency_formatter(nil, '')).to eq('')
93
+ specify 'returns formatted number' do
94
+ expect(subject.number_formatter('12345.67899', arg)).to eq('12,345.679')
95
+ expect(subject.number_formatter('12345', arg)).to eq('12,345.000')
96
+ end
84
97
  end
85
98
 
86
- specify 'returns empty string if value is empty string' do
87
- expect(subject.currency_formatter('', '')).to eq('')
88
- end
99
+ context 'localized for France' do
100
+ subject { france_formatter }
89
101
 
90
- specify 'returns formatted currency' do
91
- expect(subject.currency_formatter('12345.67', arg)).to eq('$12,345.67 USD')
102
+ let(:arg) { '3' }
103
+
104
+ specify 'returns formatted number' do
105
+ expect(subject.number_formatter('12345.67899', arg)).to eq('12 345,679')
106
+ expect(subject.number_formatter('12345', arg)).to eq('12 345,000')
107
+ end
92
108
  end
93
109
  end
94
110
 
95
- describe '#number_formatter' do
96
- subject do
97
- described_class.new(
98
- currency_code: 'USD',
99
- currency_round: 2,
100
- currency_symbol: '$'
101
- )
102
- end
111
+ describe '#currency_formatter' do
112
+ let(:arg) { '' }
103
113
 
104
- let(:arg) { '3' }
114
+ context 'localized for USA (default)' do
115
+ subject { usa_formatter }
105
116
 
106
- specify 'returns empty string if value is null' do
107
- expect(subject.currency_formatter(nil, '')).to eq('')
108
- end
117
+ specify 'returns empty string if value is null' do
118
+ expect(subject.currency_formatter(nil, arg)).to eq('')
119
+ end
109
120
 
110
- specify 'returns empty string if value is empty string' do
111
- expect(subject.currency_formatter('', '')).to eq('')
121
+ specify 'returns empty string if value is empty string' do
122
+ expect(subject.currency_formatter('', arg)).to eq('')
123
+ end
124
+
125
+ specify 'returns formatted currency' do
126
+ expect(subject.currency_formatter('12345.67', arg)).to eq('$12,345.67 USD')
127
+ end
112
128
  end
113
129
 
114
- specify 'returns formatted number' do
115
- expect(subject.number_formatter('12345.67899', arg)).to eq('12,345.679')
130
+ context 'localized for France' do
131
+ subject { france_formatter }
132
+
133
+ specify 'returns empty string if value is null' do
134
+ expect(subject.currency_formatter(nil, arg)).to eq('')
135
+ end
136
+
137
+ specify 'returns empty string if value is empty string' do
138
+ expect(subject.currency_formatter('', arg)).to eq('')
139
+ end
140
+
141
+ specify 'returns formatted currency' do
142
+ expect(subject.currency_formatter('12345.67', arg)).to eq('12 345,67 €')
143
+ end
116
144
  end
117
145
  end
118
146
 
@@ -115,11 +115,20 @@ describe Proforma::ExtendedEvaluator do
115
115
 
116
116
  actual_documents = Proforma.render(data, template, evaluator: Proforma::ExtendedEvaluator.new)
117
117
 
118
+ expected_contents = <<~CONTENTS
119
+ DETAILS FOR: BOND, JAMES (1)
120
+ ID #: 1
121
+ First Name: James
122
+ Last Name: Bond
123
+ Social Security #: XXXXXXX6789
124
+ Birthdate: 05/14/1960
125
+ Smoker: No
126
+ Balance: $123.45 USD
127
+ CONTENTS
128
+
118
129
  expected_documents = [
119
130
  Proforma::Document.new(
120
- contents: "DETAILS FOR: BOND, JAMES (1)\nID #: 1\nFirst Name: James\nLast Name:"\
121
- " Bond\nSocial Security #: XXXXXXX6789\nBirthdate: 05/14/1960\nSmoker:"\
122
- " No\nBalance: $123.45 USD\n",
131
+ contents: expected_contents,
123
132
  extension: '.txt',
124
133
  title: ''
125
134
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proforma-extended-evaluator
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.alpha
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-19 00:00:00.000000000 Z
11
+ date: 2019-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: stringento
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: proforma
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.0.0.pre.alpha
47
+ version: '1'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.0.0.pre.alpha
54
+ version: '1'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pry
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -168,9 +168,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
168
168
  version: 2.3.8
169
169
  required_rubygems_version: !ruby/object:Gem::Requirement
170
170
  requirements:
171
- - - ">"
171
+ - - ">="
172
172
  - !ruby/object:Gem::Version
173
- version: 1.3.1
173
+ version: '0'
174
174
  requirements: []
175
175
  rubygems_version: 3.0.1
176
176
  signing_key: