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

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