testcentricity_apps 4.1.0 → 4.1.1

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: 6b4e82b184c5597d7aec89e022b126b08f005daa00519c60dfd2907edaeef661
4
- data.tar.gz: 2035f556dcd2f033655c4edcf65d2ba1c7b2661cc920e052abef475178e5d681
3
+ metadata.gz: b9ac02a673f61d2ac2e77b8b24c00adfd27c73caa78ffb28e28279f311bcf838
4
+ data.tar.gz: 2bbf12bcfd0008f92dcd2a79d7a050cc6ff5fcc9dfee48b14a2e2162ec83f04f
5
5
  SHA512:
6
- metadata.gz: 783f2dff9161ff6fa835a410ed4baa0e2ad67bd8ddc5fffebaad70f85f178d82a8edf1d0cb9995156a2f1783c3c5687de71359634d99f5f13312958f5e91a848
7
- data.tar.gz: af7d790c29b515dd86af8201b1032ca6d1bc8e308453ea6c3b6ecc67d931e59e8b3d15cdca914f2cf937855827016e0f69f2ad4717a4f7733ebea3b15feffa29
6
+ metadata.gz: dbf72b0b195024e207159ed83d37086e9b1eac1d5946c93dc1950a768687bd9f12edd387c5373e52917c91a371754138b1577534a5a7c3c57b31c158ecfda974
7
+ data.tar.gz: 2890798258cb79be67cb85ebce8525504f5f19ae9378d323af2f037c578032dea5839e50bca178450895d4814e71c989c02f3635224ec5b9864f3859f9ffa26b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
4
 
5
+ ## [4.1.1] - 03-FEB-2026
6
+
7
+
8
+ ### Added
9
+ * Updated `ScreenObject.verify_ui_states` and `ScreenSection.verify_ui_states` methods to support verification of the following
10
+ `AppTable` properties:
11
+ * `rowcount`
12
+ * `columncount`
13
+ * `column_headers`
14
+ * `row`
15
+ * `column`
16
+ * `cell`
17
+ * Added `DataSource.read_file` method capable of reading from `.yml`, `.json`, `.csv`, or `.xml` data files, and accepting
18
+ `options` hash for specifying hash key and value conversions to data being read prior to passing to `DataPresenter` objects.
19
+
20
+ ### Changed
21
+ * Refactored `EnvironData.read` method to allow passing `options` hash for specifying hash key and value conversions to
22
+ data being read prior to passing to `DataPresenter` objects.
23
+ * Refactored `ScreenObject.populate_data_fields` and `ScreenSection.populate_data_fields` methods to support passing a
24
+ `Symbol` for a UI element's name to support using `DataPresenter` object attributes to source data.
25
+
26
+ ### Removed
27
+ * Unused `DataObject` class has been removed.
28
+ * Removed unused `DataSource.read_yaml_node_data` and `DataSource.read_json_node_data` methods.
29
+
30
+
5
31
  ## [4.1.0] - 09-DEC-2025
6
32
 
7
33
  ### Added
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014-2025, Tony Mrozinski
1
+ Copyright (c) 2014-2026, Tony Mrozinski
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
data/README.md CHANGED
@@ -2395,7 +2395,7 @@ is typically `mac`, `ios`, or `android`.
2395
2395
  ---
2396
2396
  ## Copyright and License
2397
2397
 
2398
- All TestCentricity™ Frameworks are Copyright (c) 2014-2025, A.J. Mrozinski.
2398
+ All TestCentricity™ Frameworks are Copyright (c) 2014-2026, A.J. Mrozinski.
2399
2399
  All rights reserved.
2400
2400
 
2401
2401
  Redistribution and use in source and binary forms, with or without
@@ -21,7 +21,7 @@ module TestCentricity
21
21
  end
22
22
 
23
23
  # Populate the specified UI elements on this screen or section object with the associated data from a Hash passed as
24
- # an argument. Data values must be in the form of a String for textfield controls. For checkboxes, radios and switches,
24
+ # an argument. Data values must be in the form of a String for textfield controls. For checkboxes,radios, and switches,
25
25
  # data must either be a Boolean or a String that evaluates to a Boolean value (Yes, No, 1, 0, true, false). For screen
26
26
  # section objects, data values must be a String, and the screen section object must have a set method defined.
27
27
  #
@@ -47,25 +47,34 @@ module TestCentricity
47
47
  # security_code_field => UserData.current.cvv
48
48
  # }
49
49
  # populate_data_fields(fields)
50
- #
51
50
  def populate_data_fields(data, wait_time = nil)
52
51
  timeout = wait_time.nil? ? 2 : wait_time
53
52
  data.each do |data_field, data_param|
54
- next if data_param.blank?
55
-
56
- # make sure the intended UI target element is visible before trying to set its value
57
- data_field.scroll_into_view unless data_field.wait_until_visible(timeout, post_exception = false)
58
- if data_param == '!DELETE'
59
- data_field.clear
60
- else
61
- case data_field.get_object_type
62
- when :checkbox
63
- data_field.set_checkbox_state(data_param.to_bool)
64
- when :radio
65
- data_field.set_selected_state(data_param.to_bool)
66
- when :textfield
53
+ unless data_param.blank?
54
+ # if data_field is a Symbol, find the corresponding object reference
55
+ if data_field.is_a?(Symbol)
56
+ begin
57
+ obj = method(data_field)
58
+ rescue
59
+ puts "No corresponding data field found for #{data_field}" if ENV['DEBUG']
60
+ next
61
+ end
62
+ data_field = obj.call
63
+ end
64
+ # make sure the intended UI target element is visible before trying to set its value
65
+ data_field.scroll_into_view unless data_field.wait_until_visible(timeout, post_exception = false)
66
+ if data_param == '!DELETE'
67
67
  data_field.clear
68
- data_field.set(data_param)
68
+ else
69
+ case data_field.get_object_type
70
+ when :checkbox
71
+ data_field.set_checkbox_state(data_param.to_bool)
72
+ when :radio
73
+ data_field.set_selected_state(data_param.to_bool)
74
+ when :textfield
75
+ data_field.clear
76
+ data_field.set(data_param)
77
+ end
69
78
  end
70
79
  end
71
80
  end
@@ -84,7 +93,7 @@ module TestCentricity
84
93
  object_states.each do |property, state|
85
94
  actual = case property
86
95
  when :visible
87
- if auto_scroll && state && !Environ.is_macos?
96
+ if auto_scroll && state
88
97
  ui_object.scroll_into_view if ui_object.hidden?
89
98
  end
90
99
  ui_object.visible?
@@ -112,12 +121,6 @@ module TestCentricity
112
121
  ui_object.read_only?
113
122
  when :maxlength
114
123
  ui_object.get_max_length
115
- when :rowcount
116
- ui_object.get_row_count
117
- when :columncount
118
- ui_object.get_column_count
119
- when :column_headers
120
- ui_object.get_header_columns
121
124
  when :items
122
125
  ui_object.get_list_items
123
126
  when :itemcount
@@ -134,14 +137,16 @@ module TestCentricity
134
137
  ui_object.count
135
138
  when :buttons
136
139
  ui_object.buttons
137
- when :identifier
138
- ui_object.identifier
139
- when :title
140
- ui_object.title
140
+ when :rowcount
141
+ ui_object.get_row_count
142
+ when :columncount
143
+ ui_object.get_column_count
144
+ when :column_headers
145
+ ui_object.get_header_columns
141
146
  when :item_data
142
147
  ui_object.get_item_data
143
148
  else
144
- if property.is_a?(Hash)
149
+ if property.is_a?(Hash)
145
150
  property.map do |key, value|
146
151
  case key
147
152
  when :item
@@ -150,12 +155,12 @@ module TestCentricity
150
155
  ui_object.get_item_enabled(value.to_i)
151
156
  when :item_data
152
157
  ui_object.get_item_data(value.to_i)
158
+ when :cell
159
+ ui_object.get_table_cell(value[0].to_i, value[1].to_i)
153
160
  when :row
154
161
  ui_object.get_table_row(value.to_i)
155
162
  when :column
156
163
  ui_object.get_table_column(value.to_i)
157
- when :cell
158
- ui_object.get_table_cell(value[0].to_i, value[1].to_i)
159
164
  else
160
165
  raise "#{key} is not a valid property key"
161
166
  end
@@ -164,11 +169,7 @@ module TestCentricity
164
169
  raise "#{property} is not a valid property"
165
170
  end
166
171
  end
167
- error_msg = if ui_object.respond_to?(:get_name)
168
- "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) #{property} property to"
169
- else
170
- "Expected '#{screen_name}' screen object #{property} property to"
171
- end
172
+ error_msg = "Expected UI object '#{ui_object.get_name}' (#{ui_object.get_locator}) #{property} property to"
172
173
  ExceptionQueue.enqueue_comparison(ui_object, state, actual, error_msg)
173
174
  end
174
175
  end
@@ -189,8 +190,7 @@ module TestCentricity
189
190
  # swipe_gesture(direction = :down, distance = 1)
190
191
  #
191
192
  def swipe_gesture(direction, distance = 0.5)
192
- raise 'Scroll distance must be between 0 and 1' if distance.negative? || distance > 1
193
-
193
+ raise 'Scroll distance must be between 0 and 1' if (distance < 0 || distance > 1)
194
194
  size = window_size
195
195
  mid_pt = [(size.width * 0.5).to_i, (size.height * 0.5).to_i]
196
196
  top = (mid_pt[1] - ((size.height * distance) * 0.5)).to_i
@@ -1,44 +1,28 @@
1
- require 'yaml'
2
- require 'json'
3
- require 'virtus'
4
- require 'time'
1
+ require 'active_support'
2
+ require 'active_support/core_ext/hash'
5
3
  require 'chronic'
6
4
  require 'faker'
5
+ require 'json'
6
+ require 'rexml/document'
7
+ require 'smarter_csv'
8
+ require 'time'
9
+ require 'virtus'
10
+ require 'yaml'
7
11
 
8
12
 
9
13
  module TestCentricity
10
14
 
11
15
  PRIMARY_DATA_PATH ||= 'config/test_data/'
16
+ SECONDARY_DATA_PATH ||= 'config/data/'
12
17
  PRIMARY_DATA_FILE ||= "#{PRIMARY_DATA_PATH}data."
13
18
  YML_PRIMARY_DATA_FILE ||= "#{PRIMARY_DATA_FILE}yml"
14
19
  JSON_PRIMARY_DATA_FILE ||= "#{PRIMARY_DATA_FILE}json"
15
20
 
16
21
 
17
- class DataObject
18
- attr_accessor :current, :context, :hash_table
19
-
20
- def initialize(data)
21
- @hash_table = data
22
- end
23
-
24
- def self.current
25
- @current
26
- end
27
-
28
- def self.current=(current)
29
- @current = current
30
- end
31
- end
32
-
33
-
34
22
  class DataPresenter
35
23
  include Virtus.model
36
24
 
37
- attr_accessor :current, :context
38
-
39
- def initialize(data)
40
- self.attributes = data unless data.nil?
41
- end
25
+ attr_accessor :current
42
26
 
43
27
  def self.current
44
28
  @current
@@ -50,47 +34,162 @@ module TestCentricity
50
34
  end
51
35
 
52
36
 
53
- # :nocov:
54
37
  class DataSource
55
- attr_accessor :file_path, :node
38
+ attr_accessor :file_path
39
+ attr_accessor :file_extension
56
40
 
57
- def read_yaml_node_data(file_name, node_name)
58
- @file_path = "#{PRIMARY_DATA_PATH}#{file_name}"
59
- @node = node_name
60
- data = YAML.load_file(@file_path)
61
- data[node_name]
41
+ def read_file(file_name, key = nil, node_name = nil, options = nil)
42
+ # check to see if full file path was specified
43
+ if File.exist?(file_name)
44
+ @file_path = file_name
45
+ else
46
+ # construct the full file path to the file to be read
47
+ @file_path = "#{PRIMARY_DATA_PATH}#{file_name}"
48
+ unless File.exist?(@file_path)
49
+ @file_path = "#{SECONDARY_DATA_PATH}#{file_name}"
50
+ raise "File #{file_name} not found in Primary or Secondary folders in config folder" unless File.exist?(@file_path)
51
+ end
52
+ end
53
+ # determine file type and read in data from file
54
+ @file_extension = File.extname(file_name)
55
+ data = case @file_extension
56
+ when '.yml'
57
+ YAML.load_file(@file_path)
58
+ when'.json'
59
+ JSON.parse(File.read(@file_path))
60
+ when '.xml'
61
+ xml_data = File.read(@file_path)
62
+ Hash.from_xml(xml_data)
63
+ when '.csv'
64
+ if options
65
+ SmarterCSV.process(@file_path, options)
66
+ else
67
+ SmarterCSV.process(@file_path)
68
+ end
69
+ else
70
+ raise "#{file_name} is not a supported file type"
71
+ end
72
+ # return data if sourced from a .csv file
73
+ return data if @file_extension == '.csv'
74
+
75
+ # read data from specified key and/or node
76
+ result = if key
77
+ raise "Key #{key} not found" unless data.key?(key)
78
+
79
+ if node_name
80
+ raise "Node #{node_name} not found" unless data[key].key?(node_name)
81
+
82
+ data[key][node_name]
83
+ else
84
+ data[key]
85
+ end
86
+ else
87
+ data
88
+ end
89
+ self.class.send(:process_data, result, options)
62
90
  end
63
91
 
64
- def read_json_node_data(file_name, node_name)
65
- @file_path = "#{PRIMARY_DATA_PATH}#{file_name}"
66
- @node = node_name
67
- raw_data = File.read(@file_path)
68
- data = JSON.parse(raw_data)
69
- data[node_name]
92
+ private
93
+
94
+ def self.process_data(data, options)
95
+ # calculate dynamic values if any are specified
96
+ if data.is_a?(Hash)
97
+ data.each do |key, value|
98
+ data[key] = calculate_dynamic_value(value) if value.to_s.start_with?('eval!')
99
+ end
100
+ end
101
+ return data unless options
102
+
103
+ # convert keys to symbols if :keys_as_symbols is true in options
104
+ if options.key?(:keys_as_symbols) && options[:keys_as_symbols]
105
+ data.transform_keys!(&:to_sym)
106
+ end
107
+ # convert values if :value_converters are specified in options
108
+ if options.key?(:value_converters)
109
+ map_values(data, options[:value_converters])
110
+ else
111
+ data
112
+ end
70
113
  end
71
114
 
72
- private
115
+ def self.map_values(data, value_converters)
116
+ data.each_with_object({}) do |(k, v), new_hash|
117
+ converter = value_converters[k]
118
+ v = converter.convert(v) if converter
119
+ new_hash[k] = v
120
+ end
121
+ end
73
122
 
74
123
  def self.calculate_dynamic_value(value)
75
124
  test_value = value.split('!', 2)
76
125
  parameter = test_value[1].split('.', 2)
77
- case parameter[0]
78
- when 'Date'
79
- result = eval("Chronic.parse('#{parameter[1]}')")
80
- when 'FormattedDate', 'FormatDate'
81
- date_time_params = parameter[1].split(' format! ', 2)
82
- date_time = eval("Chronic.parse('#{date_time_params[0].strip}')")
83
- result = date_time.to_s.format_date_time("#{date_time_params[1].strip}")
84
- else
85
- result = if Faker.constants.include?(parameter[0].to_sym)
126
+ result = case parameter[0]
127
+ when 'Date'
128
+ Chronic.parse(parameter[1])
129
+ when 'FormattedDate', 'FormatDate'
130
+ date_time_params = parameter[1].split(' format! ', 2)
131
+ date_time = Chronic.parse(date_time_params[0].strip)
132
+ date_time.to_s.format_date_time("#{date_time_params[1].strip}")
133
+ else
134
+ if Faker.constants.include?(parameter[0].to_sym)
86
135
  eval("Faker::#{parameter[0]}.#{parameter[1]}")
87
136
  else
88
137
  eval(test_value[1])
89
138
  end
90
- end
139
+ end
91
140
  result.to_s
92
141
  end
93
142
  end
94
- # :nocov:
95
143
  end
96
144
 
145
+
146
+ # perform conversion of String to Boolean when reading data from .csv or .xml files
147
+ class ToBoolean
148
+ def self.convert(value)
149
+ value.to_bool unless value.nil?
150
+ end
151
+ end
152
+
153
+
154
+ # perform conversion of Integer to String when reading data from .csv or .xml files
155
+ class ToString
156
+ def self.convert(value)
157
+ if value.is_a? Integer
158
+ value.to_s
159
+ else
160
+ value
161
+ end
162
+ end
163
+ end
164
+
165
+
166
+ # perform conversion of String to Integer when reading data from .csv or .xml files
167
+ class ToInteger
168
+ def self.convert(value)
169
+ if value.is_a? Integer
170
+ value
171
+ else
172
+ if value.is_int?
173
+ value.to_i
174
+ else
175
+ value
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+
182
+ # perform conversion of String to Float when reading data from .csv or .xml files
183
+ class ToFloat
184
+ def self.convert(value)
185
+ if value.is_a? Float
186
+ value
187
+ else
188
+ if value.is_float?
189
+ value.to_f
190
+ else
191
+ value
192
+ end
193
+ end
194
+ end
195
+ end
@@ -20,8 +20,7 @@ module TestCentricity
20
20
  read('Environments', environ_name)
21
21
  when :json
22
22
  # read generic test data from data.json file
23
- raw_data = File.read(JSON_PRIMARY_DATA_FILE)
24
- @generic_data = JSON.parse(raw_data)
23
+ @generic_data = JSON.parse(File.read(JSON_PRIMARY_DATA_FILE))
25
24
  # read environment specific test data
26
25
  data_file = "#{PRIMARY_DATA_PATH}#{environ_name}_data.json"
27
26
  @environ_specific_data = if File.exist?(data_file)
@@ -39,27 +38,21 @@ module TestCentricity
39
38
  Environ.current = @current
40
39
  end
41
40
 
42
- def self.read(key_name, node_name)
43
- if @environ_specific_data.key?(key_name) && @environ_specific_data[key_name].key?(node_name)
44
- node_data = @environ_specific_data[key_name][node_name]
45
- else
46
- raise "No key named #{key_name} in generic and environment-specific data" unless @generic_data.key?(key_name)
47
- raise "No node named #{node_name} in #{key_name} section of generic and environment-specific data" unless @generic_data[key_name].key?(node_name)
48
-
49
- node_data = @generic_data[key_name][node_name]
50
- end
41
+ def self.read(key_name, node_name, options = nil)
42
+ node_data = if @environ_specific_data.key?(key_name) && @environ_specific_data[key_name].key?(node_name)
43
+ @environ_specific_data[key_name][node_name]
44
+ else
45
+ raise "No key named #{key_name} in generic and environment-specific data" unless @generic_data.key?(key_name)
46
+ raise "No node named #{node_name} in #{key_name} section of generic and environment-specific data" unless @generic_data[key_name].key?(node_name)
51
47
 
52
- if node_data.is_a?(Hash)
53
- node_data.each do |key, value|
54
- node_data[key] = calculate_dynamic_value(value) if value.to_s.start_with?('eval!')
55
- end
56
- end
57
- node_data
48
+ @generic_data[key_name][node_name]
49
+ end
50
+ process_data(node_data, options)
58
51
  end
59
52
  end
60
53
 
61
54
 
62
- class Environ < TestCentricity::DataObject
55
+ class Environ
63
56
  @session_id = Time.now.strftime('%d%H%M%S%L')
64
57
  @session_time_stamp = Time.now.strftime('%Y%m%d%H%M%S')
65
58
  @test_environment = ENV['TEST_ENVIRONMENT']
@@ -68,6 +61,7 @@ module TestCentricity
68
61
  @language = ENV['LANGUAGE'] || 'English'
69
62
  @screen_shots = []
70
63
 
64
+ attr_accessor :current
71
65
  attr_accessor :test_environment, :session_state, :session_code, :app_session_id, :os, :device, :device_name, :device_type, :device_os, :device_os_version, :device_orientation, :screen_size, :platform, :driver, :driver_name, :appium_driver, :tunneling, :locale, :language, :parallel, :process_num, :signed_in, :portal_status, :portal_context, :user_id, :password, :app_id, :api_key, :option1, :option2, :option3, :option4, :dns, :db_username, :db_password, :ios_app_path, :ios_ipa_path, :ios_bundle_id, :ios_test_id, :android_apk_path, :android_app_id, :android_test_id, :default_max_wait_time, :deep_link_prefix, :mac_bundle_id
72
66
 
73
67
  def initialize(data)
@@ -91,8 +85,14 @@ module TestCentricity
91
85
  @android_test_id = data['ANDROID_TEST_ID']
92
86
  @deep_link_prefix = data['DEEP_LINK_PREFIX']
93
87
  @mac_bundle_id = data['MAC_BUNDLE_ID']
88
+ end
89
+
90
+ def self.current
91
+ @current
92
+ end
94
93
 
95
- super
94
+ def self.current=(current)
95
+ @current = current
96
96
  end
97
97
 
98
98
  def self.new_app_session
@@ -1,3 +1,3 @@
1
1
  module TestCentricityApps
2
- VERSION = '4.1.0'
2
+ VERSION = '4.1.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testcentricity_apps
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - A.J. Mrozinski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-10 00:00:00.000000000 Z
11
+ date: 2026-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 10.1.1
33
+ version: 10.2.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 10.1.1
40
+ version: 10.2.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: parallel_tests
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 4.38.0
103
+ version: 4.39.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 4.38.0
110
+ version: 4.39.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: simplecov
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -136,20 +136,34 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: 0.9.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: activesupport
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '4.0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '4.0'
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: appium_lib
141
155
  requirement: !ruby/object:Gem::Requirement
142
156
  requirements:
143
157
  - - "~>"
144
158
  - !ruby/object:Gem::Version
145
- version: 16.1.0
159
+ version: 16.1.1
146
160
  type: :runtime
147
161
  prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
164
  - - "~>"
151
165
  - !ruby/object:Gem::Version
152
- version: 16.1.0
166
+ version: 16.1.1
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: childprocess
155
169
  requirement: !ruby/object:Gem::Requirement
@@ -220,6 +234,20 @@ dependencies:
220
234
  - - ">="
221
235
  - !ruby/object:Gem::Version
222
236
  version: '0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: smarter_csv
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :runtime
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
223
251
  - !ruby/object:Gem::Dependency
224
252
  name: test-unit
225
253
  requirement: !ruby/object:Gem::Requirement