lucarecord 0.2.14 → 0.2.19

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: 1b2e7e80da19b8c0adaebc6272a05e26f66c2e6a989fa416bfd77951ac5f88a0
4
- data.tar.gz: 699708346c68e5fa32105eec0d8a82aae8fd85c452f005a402f80a9ff7b19b95
3
+ metadata.gz: e5d79527ced912cddc0f5d33e7d557dd23fb2e2ae0ed0437f7c90eb44095469e
4
+ data.tar.gz: ce8fc1c4ec1264913024981a6769a36d6439d6d5b89a820bcfa7fcb6991151bb
5
5
  SHA512:
6
- metadata.gz: 59217fdab9258c37ceab07e35118961ae3ac6d6d1587f84235b31169dacf8a82f968a2e8b00f0710c0f7e587836d7d4834f4bf8d2f51e5fbd6f30d1a3100ea7b
7
- data.tar.gz: edbc54ec5c66e422a6975c8e53a33b32a063304d5c582ebf4f22596151d141de7d90404eaff8cdd7e8b10264f195da67803ba48a2e4426c6629d995f6cc03507
6
+ metadata.gz: f4f62de1a08971733954c469d2572f6aab8018379de928ab2413aca14d9123b08da67e5f85dcd8bf632c646732cf5c534f259bd83fb5eeff0d851e4d444b7e1c
7
+ data.tar.gz: 2ef832f91abef366760fbff0157c97c9e43a814b1df6f1c5244e0e0f7ad32db8459f2abee51fd1fd40812283b87b6b2a1140d6668b98ab98d86088d17d3bb0e4
@@ -0,0 +1,13 @@
1
+ ## LucaRecord 0.2.19
2
+
3
+ * `LucaSupport::Code.decode_id()`
4
+ * `LucaSupport::Code.encode_term()` for multiple months search. Old `scan_term()` removed.
5
+
6
+ ## LucaRecord 0.2.18
7
+
8
+ * `find()`, `create()`, `save()` now supports both of uuid / historical records. If specified `date:` keyword option to `create()`, then generate historical record. `find()`, `save()` identifies with 'id' attribute.
9
+
10
+ ## LucaRecord 0.2.17
11
+
12
+ * Change internal number format to BigDecimal.
13
+ * Number of Decimal is configurable through `decimal_number` in config.yml(default = 2). `country` setting can also affect.
@@ -1,4 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
3
+ require 'luca_support'
4
+ require 'luca_support/config'
2
5
  require 'luca_record/version'
3
6
 
4
7
  module LucaRecord
@@ -14,13 +14,13 @@ module LucaRecord
14
14
  include LucaSupport::Code
15
15
 
16
16
  def initialize(file = @filename)
17
- @path = file
18
- #@path = dict_path(file)
17
+ #@path = file
18
+ @path = self.class.dict_path(file)
19
19
  set_driver
20
20
  end
21
21
 
22
22
  def search(word, default_word = nil)
23
- res = max_score_code(word)
23
+ res = max_score_code(word.gsub(/[[:space:]]/, ''))
24
24
  if res[1] > 0.4
25
25
  res[0]
26
26
  else
@@ -65,7 +65,7 @@ module LucaRecord
65
65
  config[:type] ||= 'invalid'
66
66
  config[:debit_value] = @config['debit_value'].to_i if @config.dig('debit_value')
67
67
  config[:credit_value] = @config['credit_value'].to_i if @config.dig('credit_value')
68
- config[:note] = @config['note'].to_i if @config.dig('note')
68
+ config[:note] = @config['note'] if @config.dig('note')
69
69
  config[:encoding] = @config['encoding'] if @config.dig('encoding')
70
70
 
71
71
  config[:year] = @config['year'] if @config.dig('year')
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'bigdecimal'
3
4
  require 'csv'
4
5
  require 'date'
5
6
  require 'fileutils'
@@ -20,24 +21,24 @@ module LucaRecord # :nodoc:
20
21
  end
21
22
 
22
23
  module ClassMethods
23
- #-----------------------------------------------------------------
24
+ # ----------------------------------------------------------------
24
25
  # :section: Query Methods
25
26
  # Provide sematic search interfaces.
26
27
  # <tt>basedir</tt> is set by class instance variable <tt>@dirname</tt>
27
28
  # of each concrete class.
28
- #-----------------------------------------------------------------
29
+ # ----------------------------------------------------------------
29
30
 
30
31
  # find ID based record. Support uuid and encoded date.
31
32
  def find(id, basedir = @dirname)
32
- return enum_for(:find, id, basedir) unless block_given?
33
+ return enum_for(:find, id, basedir).first unless block_given?
33
34
 
34
35
  if id.length >= 40
35
36
  open_hashed(basedir, id) do |f|
36
37
  yield load_data(f)
37
38
  end
38
- elsif id.length >= 9
39
- # TODO: need regexp match for more flexible coding(after AD9999)
40
- open_records(basedir, id[0, 5], id[5, 6]) do |f, path|
39
+ elsif id.length >= 7
40
+ parts = id.split('/')
41
+ open_records(basedir, parts[0], parts[1]) do |f, path|
41
42
  yield load_data(f, path)
42
43
  end
43
44
  else
@@ -53,8 +54,22 @@ module LucaRecord # :nodoc:
53
54
  def asof(year, month = nil, day = nil, basedir = @dirname)
54
55
  return enum_for(:search, year, month, day, nil, basedir) unless block_given?
55
56
 
56
- search(year, month, day, nil, basedir) do |data, path|
57
- yield data, path
57
+ search(year, month, day, nil, basedir) { |data, path| yield data, path }
58
+ end
59
+
60
+ # scan ranging data on multiple months
61
+ #
62
+ def term(start_year, start_month, end_year, end_month, code = nil, basedir = @dirname)
63
+ return enum_for(:term, start_year, start_month, end_year, end_month, code, basedir) unless block_given?
64
+
65
+ LucaSupport::Code.encode_term(start_year, start_month, end_year, end_month).each do |subdir|
66
+ open_records(basedir, subdir, nil, code) do |f, path|
67
+ if @record_type == 'raw'
68
+ yield f, path
69
+ else
70
+ yield load_data(f, path)
71
+ end
72
+ end
58
73
  end
59
74
  end
60
75
 
@@ -78,65 +93,117 @@ module LucaRecord # :nodoc:
78
93
  def all(basedir = @dirname)
79
94
  return enum_for(:all, basedir) unless block_given?
80
95
 
81
- open_all(basedir) do |f|
96
+ open_all(basedir) do |f|
82
97
  yield load_data(f)
83
98
  end
84
99
  end
85
100
 
86
- #-----------------------------------------------------------------
101
+ # ----------------------------------------------------------------
87
102
  # :section: Write Methods
88
103
  # <tt>basedir</tt> is set by class instance variable <tt>@dirname</tt>
89
104
  # of each concrete class.
90
- #-----------------------------------------------------------------
91
-
92
- # create hash based record
93
- def create(obj, basedir = @dirname)
94
- id = LucaSupport::Code.issue_random_id
95
- obj['id'] = id
96
- open_hashed(basedir, id, 'w') do |f|
97
- f.write(YAML.dump(obj.sort.to_h))
98
- end
99
- id
100
- end
105
+ # ----------------------------------------------------------------
101
106
 
102
- # define new transaction ID & write data at once
103
- def create_record!(obj, date_obj, codes = nil, basedir = @dirname)
104
- gen_record_file!(basedir, date_obj, codes) do |f|
105
- f.write(YAML.dump(obj.sort.to_h))
107
+ # create record both of uuid/date identified.
108
+ #
109
+ def create(obj, date: nil, codes: nil, basedir: @dirname)
110
+ validate_keys(obj)
111
+ if date
112
+ create_record(obj, date, codes, basedir)
113
+ else
114
+ obj['id'] = LucaSupport::Code.issue_random_id
115
+ open_hashed(basedir, obj['id'], 'w') do |f|
116
+ f.write(YAML.dump(LucaSupport::Code.readable(obj.sort.to_h)))
117
+ end
118
+ obj['id']
106
119
  end
107
120
  end
108
121
 
109
122
  def prepare_dir!(basedir, date_obj)
110
- dir_name = (Pathname(basedir) + encode_dirname(date_obj)).to_s
123
+ dir_name = (Pathname(basedir) + LucaSupport::Code.encode_dirname(date_obj)).to_s
111
124
  FileUtils.mkdir_p(dir_name) unless Dir.exist?(dir_name)
112
125
  dir_name
113
126
  end
114
127
 
115
128
  def add_status!(id, status, basedir = @dirname)
116
129
  path = abs_path(basedir) / id2path(id)
117
- origin = YAML.load_file(path, {})
130
+ origin = YAML.load_file(path, **{})
118
131
  newline = { status => DateTime.now.to_s }
119
132
  origin['status'] = [] if origin['status'].nil?
120
133
  origin['status'] << newline
121
134
  File.write(path, YAML.dump(origin.sort.to_h))
122
135
  end
123
136
 
124
- #-----------------------------------------------------------------
137
+ # update file with obj['id']
138
+ def save(obj, basedir = @dirname)
139
+ if obj['id'].nil?
140
+ create(obj, basedir)
141
+ else
142
+ validate_keys(obj)
143
+ if obj['id'].length < 40
144
+ parts = obj['id'].split('/')
145
+ raise 'invalid ID' if parts.length != 2
146
+
147
+ open_records(basedir, parts[0], parts[1], nil, 'w') do |f, path|
148
+ f.write(YAML.dump(LucaSupport::Code.readable(obj.sort.to_h)))
149
+ end
150
+ else
151
+ open_hashed(basedir, obj['id'], 'w') do |f|
152
+ f.write(YAML.dump(LucaSupport::Code.readable(obj.sort.to_h)))
153
+ end
154
+ end
155
+ end
156
+ obj['id']
157
+ end
158
+
159
+ # delete file by id
160
+ def delete(id, basedir = @dirname)
161
+ FileUtils.rm(Pathname(abs_path(basedir)) / id2path(id))
162
+ id
163
+ end
164
+
165
+ # change filename with new code set
166
+ #
167
+ def change_codes(id, new_codes, basedir = @dirname)
168
+ raise 'invalid id' if id.split('/').length != 2
169
+
170
+ newfile = new_codes.empty? ? id : id + '-' + new_codes.join('-')
171
+ Dir.chdir(abs_path(basedir)) do
172
+ origin = Dir.glob("#{id}*")
173
+ raise 'duplicated files' if origin.length != 1
174
+
175
+ File.rename(origin.first, newfile)
176
+ end
177
+ newfile
178
+ end
179
+
180
+ # ----------------------------------------------------------------
125
181
  # :section: Path Utilities
126
- #-----------------------------------------------------------------
182
+ # ----------------------------------------------------------------
127
183
 
128
- # convert ID to file path. Normal argument is as follows:
184
+ # Convert ID to file directory/filename path.
185
+ # 1st element of Array is used as directory, the others as filename.
186
+ # String without '/' is converted as git-like structure.
187
+ # Normal argument is as follows:
129
188
  #
130
- # [2020H, V001]
131
- # "2020H/V001"
132
- # "a7b806d04a044c6dbc4ce72932867719"
189
+ # ['2020H', 'V001', 'a7b806d04a044c6dbc4ce72932867719']
190
+ # => '2020H/V001-a7b806d04a044c6dbc4ce72932867719'
191
+ # 'a7b806d04a044c6dbc4ce72932867719'
192
+ # => 'a7b/806d04a044c6dbc4ce72932867719'
193
+ # '2020H/V001'
194
+ # => '2020H/V001'
133
195
  def id2path(id)
134
196
  if id.is_a?(Array)
135
- id.join('/')
197
+ case id.length
198
+ when 0..2
199
+ id.join('/')
200
+ else
201
+ [id[0], id[1..-1].join('-')].join('/')
202
+ end
136
203
  elsif id.include?('/')
137
204
  id
138
205
  else
139
- encode_hashed_path(id)
206
+ encode_hashed_path(id).join('/')
140
207
  end
141
208
  end
142
209
 
@@ -150,10 +217,6 @@ module LucaRecord # :nodoc:
150
217
  end
151
218
  end
152
219
 
153
- def encode_dirname(date_obj)
154
- date_obj.year.to_s + LucaSupport::Code.encode_month(date_obj)
155
- end
156
-
157
220
  # test if having required dirs/files under exec path
158
221
  def valid_project?(path = LucaSupport::Config::Pjdir)
159
222
  project_dir = Pathname(path)
@@ -166,6 +229,29 @@ module LucaRecord # :nodoc:
166
229
 
167
230
  private
168
231
 
232
+ # define new transaction ID & write data at once
233
+ # ID format is like '2020H/A001', which means record no.1 of 2020/10/10.
234
+ # Any data format can be written with block.
235
+ #
236
+ def create_record(obj, date_obj, codes = nil, basedir = @dirname)
237
+ FileUtils.mkdir_p(abs_path(basedir)) unless Dir.exist?(abs_path(basedir))
238
+ subdir = "#{date_obj.year}#{LucaSupport::Code.encode_month(date_obj)}"
239
+ filename = LucaSupport::Code.encode_date(date_obj) + new_record_id(basedir, date_obj)
240
+ obj['id'] = "#{subdir}/#{filename}" if obj.is_a? Hash
241
+ filename += '-' + codes.join('-') if codes
242
+ Dir.chdir(abs_path(basedir)) do
243
+ FileUtils.mkdir_p(subdir) unless Dir.exist?(subdir)
244
+ File.open(Pathname(subdir) / filename, 'w') do |f|
245
+ if block_given?
246
+ yield(f)
247
+ else
248
+ f.write(YAML.dump(LucaSupport::Code.readable(obj.sort.to_h)))
249
+ end
250
+ end
251
+ end
252
+ "#{subdir}/#{filename}"
253
+ end
254
+
169
255
  # open records with 'basedir/month/date-code' path structure.
170
256
  # Glob pattern can be specified like folloing examples.
171
257
  #
@@ -181,6 +267,7 @@ module LucaRecord # :nodoc:
181
267
 
182
268
  file_pattern = filename.nil? ? '*' : "#{filename}*"
183
269
  Dir.chdir(abs_path(basedir)) do
270
+ FileUtils.mkdir_p(subdir) if mode == 'w' && !Dir.exist?(subdir)
184
271
  Dir.glob("#{subdir}*/#{file_pattern}").sort.each do |subpath|
185
272
  next if skip_on_unmatch_code(subpath, code)
186
273
 
@@ -212,6 +299,17 @@ module LucaRecord # :nodoc:
212
299
  end
213
300
  end
214
301
 
302
+ # parse data dir and respond existing months
303
+ #
304
+ def scan_terms(query = nil, base_dir = @dirname)
305
+ pattern = query.nil? ? "*" : "#{query}*"
306
+ Dir.chdir(abs_path(base_dir)) do
307
+ Dir.glob(pattern).select { |dir|
308
+ FileTest.directory?(dir) && /^[0-9]/.match(dir)
309
+ }.sort.map { |str| decode_term(str) }
310
+ end
311
+ end
312
+
215
313
  # Decode basic format.
216
314
  # If specific decode is needed, override this method in each class.
217
315
  #
@@ -223,18 +321,18 @@ module LucaRecord # :nodoc:
223
321
  when 'json'
224
322
  # TODO: implement JSON parse
225
323
  else
226
- YAML.load(io.read)
324
+ LucaSupport::Code.decimalize(YAML.load(io.read)).tap { |obj| validate_keys(obj) }
227
325
  end
228
326
  end
229
327
 
230
- def gen_record_file!(basedir, date_obj, codes = nil)
231
- d = prepare_dir!(abs_path(basedir), date_obj)
232
- filename = LucaSupport::Code.encode_date(date_obj) + new_record_id(abs_path(basedir), date_obj)
233
- if codes
234
- filename += codes.inject('') { |fragment, code| "#{fragment}-#{code}" }
328
+ def validate_keys(obj)
329
+ return nil unless @required
330
+
331
+ keys = obj.keys
332
+ [].tap do |errors|
333
+ @required.each { |r| errors << r unless keys.include?(r) }
334
+ raise "Missing keys: #{errors.join(' ')}" unless errors.empty?
235
335
  end
236
- path = Pathname(d) + filename
237
- File.open(path.to_s, 'w') { |f| yield(f) }
238
336
  end
239
337
 
240
338
  # TODO: replace with data_dir method
@@ -254,8 +352,10 @@ module LucaRecord # :nodoc:
254
352
 
255
353
  # AUTO INCREMENT
256
354
  def new_record_no(basedir, date_obj)
257
- dir_name = (Pathname(basedir) + encode_dirname(date_obj)).to_s
258
- raise 'No target dir exists.' unless Dir.exist?(dir_name)
355
+ raise 'No target dir exists.' unless Dir.exist?(abs_path(basedir))
356
+
357
+ dir_name = (Pathname(abs_path(basedir)) / LucaSupport::Code.encode_dirname(date_obj)).to_s
358
+ return 1 unless Dir.exist?(dir_name)
259
359
 
260
360
  Dir.chdir(dir_name) do
261
361
  last_file = Dir.glob("#{LucaSupport::Code.encode_date(date_obj)}*").max
@@ -287,17 +387,6 @@ module LucaRecord # :nodoc:
287
387
  end
288
388
  end
289
389
 
290
- # parse data dir and respond existing months
291
- #
292
- def scan_terms(base_dir, query = nil)
293
- pattern = query.nil? ? "*" : "#{query}*"
294
- Dir.chdir(base_dir) do
295
- Dir.glob(pattern).select { |dir|
296
- FileTest.directory?(dir) && /^[0-9]/.match(dir)
297
- }.sort.map { |str| decode_term(str) }
298
- end
299
- end
300
-
301
390
  def load_config(path = nil)
302
391
  path = path.to_s
303
392
  if File.exist?(path)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LucaRecord
4
- VERSION = '0.2.14'
4
+ VERSION = '0.2.19'
5
5
  end
@@ -3,16 +3,24 @@
3
3
  require 'date'
4
4
  require 'securerandom'
5
5
  require 'digest/sha1'
6
+ require 'luca_support/config'
6
7
 
7
8
  # implement Luca IDs convention
8
9
  module LucaSupport
9
10
  module Code
10
11
  module_function
11
12
 
13
+ # Parse historical id into Array of date & transaction id.
14
+ #
15
+ def decode_id(id_str)
16
+ m = %r(^(?<year>[0-9]+)(?<month>[A-L])/?(?<day>[0-9A-V])(?<txid>[0-9A-Z]{,3})).match(id_str)
17
+ ["#{m[:year]}-#{decode_month(m[:month])}-#{decode_date(m[:day])}", decode_txid(m[:txid])]
18
+ end
19
+
12
20
  def encode_txid(num)
13
21
  txmap = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
14
22
  l = txmap.length
15
- txmap[num / (l**2)] + txmap[(num%(l**2)) / l] + txmap[num % l]
23
+ txmap[num / (l**2)] + txmap[(num % (l**2)) / l] + txmap[num % l]
16
24
  end
17
25
 
18
26
  def decode_txid(id)
@@ -44,7 +52,12 @@ module LucaSupport
44
52
  num.to_s.reverse.gsub!(/(\d{3})(?=\d)/, '\1,').reverse!
45
53
  end
46
54
 
55
+ # encode directory name from year and month.
47
56
  #
57
+ def encode_dirname(date_obj)
58
+ date_obj.year.to_s + encode_month(date_obj)
59
+ end
60
+
48
61
  # Month to code conversion.
49
62
  # Date, DateTime, String, Integer is valid input. If nil, returns empty String for consistency.
50
63
  #
@@ -63,6 +76,16 @@ module LucaSupport
63
76
  '0ABCDEFGHIJKL'.index(char)
64
77
  end
65
78
 
79
+ # Generate globbing phrase like ["2020[C-H]"] for range search.
80
+ #
81
+ def encode_term(start_year, start_month, end_year, end_month)
82
+ (start_year..end_year).to_a.map do |y|
83
+ g1 = y == start_year ? encode_month(start_month) : encode_month(1)
84
+ g2 = y == end_year ? encode_month(end_month) : encode_month(12)
85
+ "#{y}[#{g1}-#{g2}]"
86
+ end
87
+ end
88
+
66
89
  def decode_term(char)
67
90
  m = /^([0-9]{4})([A-La-l])/.match(char)
68
91
  [m[1].to_i, decode_month(m[2])]
@@ -72,8 +95,40 @@ module LucaSupport
72
95
  Digest::SHA1.hexdigest(SecureRandom.uuid)
73
96
  end
74
97
 
98
+ def decimalize(obj)
99
+ case obj.class.name
100
+ when 'Array'
101
+ obj.map { |i| decimalize(i) }
102
+ when 'Hash'
103
+ obj.inject({}) { |h, (k, v)| h[k] = decimalize(v); h }
104
+ when 'Integer'
105
+ BigDecimal(obj.to_s)
106
+ when 'String'
107
+ /^[0-9\.]+$/.match(obj) ? BigDecimal(obj) : obj
108
+ when 'Float'
109
+ raise 'already float'
110
+ else
111
+ obj
112
+ end
113
+ end
114
+
115
+ def readable(obj, len = LucaSupport::Config::DECIMAL_NUM)
116
+ case obj.class.name
117
+ when 'Array'
118
+ obj.map { |i| readable(i) }
119
+ when 'Hash'
120
+ obj.inject({}) { |h, (k, v)| h[k] = readable(v); h }
121
+ when 'BigDecimal'
122
+ parts = obj.round(len).to_s('F').split('.')
123
+ len < 1 ? parts.first : "#{parts[0]}.#{parts[1][0, len]}"
124
+ else
125
+ obj
126
+ end
127
+ end
128
+
75
129
  #
76
- # convert effective/defunct data into current hash on @date
130
+ # convert effective/defunct data into current hash on @date.
131
+ # not parse nested children.
77
132
  #
78
133
  def parse_current(dat)
79
134
  {}.tap do |processed|
@@ -92,11 +147,11 @@ module LucaSupport
92
147
  # - effective: 2020-1-1
93
148
  # rank: 5
94
149
  # point: 1000
95
- # => { 'effective' => 2020-1-1, 'rank' => 5, '' => 'point' => 1000 }
150
+ # => { 'effective' => 2020-1-1, 'rank' => 5, 'point' => 1000 }
96
151
  #
97
152
  def take_current(dat, item)
98
153
  target = dat.dig(item)
99
- if target.class.name == 'Array' && target.map(&:keys).flatten.include?('effective')
154
+ if target.is_a?(Array) && target.map(&:keys).flatten.include?('effective')
100
155
  latest = target
101
156
  .filter { |a| Date.parse(a.dig('effective').to_s) < @date }
102
157
  .max { |a, b| Date.parse(a.dig('effective').to_s) <=> Date.parse(b.dig('effective').to_s) }
@@ -1,11 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'pathname'
4
+ require 'yaml'
5
+
3
6
  #
4
7
  # startup config
5
8
  #
6
9
  module LucaSupport
7
10
  module Config
8
11
  # Project top directory.
9
- Pjdir = Dir.pwd.freeze
12
+ Pjdir = ENV['LUCA_TEST_DIR'] || Dir.pwd.freeze
13
+ if File.exist?(Pathname(Pjdir) / 'config.yml')
14
+ # DECIMAL_NUM = YAML.load_file(Pathname(Pjdir) / 'config.yml', **{})['decimal_number']
15
+ COUNTRY = YAML.load_file(Pathname(Pjdir) / 'config.yml', **{})['country']
16
+ DECIMAL_NUM ||= 0 if COUNTRY == 'jp'
17
+ end
18
+ DECIMAL_NUM ||= 2
10
19
  end
11
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lucarecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.14
4
+ version: 0.2.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuma Takahiro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-07 00:00:00.000000000 Z
11
+ date: 2020-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mail
@@ -28,44 +28,44 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.17'
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
40
  version: '1.17'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 12.3.3
47
+ version: '5.0'
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: 12.3.3
54
+ version: '5.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: minitest
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '5.0'
61
+ version: 12.3.3
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '5.0'
68
+ version: 12.3.3
69
69
  description: 'ERP File operation framework
70
70
 
71
71
  '