bmg 0.23.5 → 0.23.6

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: cb0b47d8dbd6924eb1f4fb7e773635a5d1fc83fc09b09c60ead3ac913bbd2051
4
- data.tar.gz: ad0919fc045b59b5299254d0f476b31390069b6d39e086334cd55790eedf56e0
3
+ metadata.gz: a4cb86461e5f53734d08dcb3668bd2a99630680d7213bb946fa5a13cbf0f86f2
4
+ data.tar.gz: f9a80e014cb2769d6d8da8cea581b18c7601c2d1015db18e1eac6333f8e08876
5
5
  SHA512:
6
- metadata.gz: 1fa7c3dfa036762e82dd86275c522af811eba747901f288e8b1804388ddee0094350374795527b0884cf8d5355eea649f9c3ce4a66ec7c9742eeaef5fff81a16
7
- data.tar.gz: 5cee0487c9e70df6a049791ef48d93fda5ff516d769b7f8d25f9ea6f29d9d780bec8aebca78a8e88e435113acde6860fc1c7dbbbb2c9bb7f70edf88d22bfe739
6
+ metadata.gz: 7621e13e58615206096b3f2d2799a79aa4e662592688b295329bf09626efe86b9a8f4f6f01aba5432513e6054c7568894f13dfccd86d8932f28fa1e9b0892a28
7
+ data.tar.gz: 9cfc8e393267db43d44764db894b47639d6cfc445b3e7d80e1287929e02cf8ec4d7e541432f52905002953ac727770b5c30b3c4c850ff1a039d98beba2811469
@@ -3,7 +3,9 @@ module Bmg
3
3
  class DataFolder < Database
4
4
 
5
5
  DEFAULT_OPTIONS = {
6
- data_extensions: ['json', 'yml', 'yaml', 'csv']
6
+ data_extensions: ['json', 'yml', 'yaml', 'csv'],
7
+ relname_from_file: ->(file) { file.basename.rm_ext.to_sym },
8
+ filename_from_relname: ->(relname) { relname },
7
9
  }
8
10
 
9
11
  def initialize(folder, options = {})
@@ -25,15 +27,21 @@ module Bmg
25
27
  next unless @options[:data_extensions].find {|ext|
26
28
  path.ext == ".#{ext}" || path.ext == ext
27
29
  }
28
- yield(path.basename.rm_ext.to_sym, read_file(path))
30
+ yield(@options[:relname_from_file].call(path), read_file(path))
29
31
  end
30
32
  end
31
33
 
32
- def self.dump(database, path, ext = :json)
34
+ def self.dump(database, path, ext = :json, options = DEFAULT_OPTIONS)
35
+ options = DEFAULT_OPTIONS.merge(options)
33
36
  path = Path(path)
34
37
  path.mkdir_p
35
38
  database.each_relation_pair do |name, rel|
36
- (path/"#{name}.#{ext}").write(rel.public_send(:"to_#{ext}"))
39
+ filename = options[:filename_from_relname].call(name)
40
+ if ext === :json
41
+ (path/"#{filename}.#{ext}").write(JSON.pretty_generate(rel))
42
+ else
43
+ (path/"#{filename}.#{ext}").write(rel.public_send(:"to_#{ext}"))
44
+ end
37
45
  end
38
46
  path
39
47
  end
@@ -56,8 +64,8 @@ module Bmg
56
64
  def find_file(name)
57
65
  exts = @options[:data_extensions]
58
66
  exts.each do |ext|
59
- target = @folder/"#{name}.#{ext}"
60
- return target if target.file?
67
+ target = @folder.glob("*#{name}.#{ext}")
68
+ return target.first if target&.first&.file?
61
69
  end
62
70
  raise NotSuchRelationError, "#{@folder}/#{name}.#{exts.join(',')}"
63
71
  end
@@ -3,12 +3,13 @@ module Bmg
3
3
  class Xlsx < Database
4
4
 
5
5
  DEFAULT_OPTIONS = {
6
+ reader_options: {}
6
7
  }
7
8
 
8
9
  def initialize(path, options = {})
9
10
  path = Path(path) if path.is_a?(String)
10
11
  @path = path
11
- @options = options.merge(DEFAULT_OPTIONS)
12
+ @options = DEFAULT_OPTIONS.merge(options)
12
13
  end
13
14
 
14
15
  def method_missing(name, *args, &bl)
@@ -33,7 +34,9 @@ module Bmg
33
34
  end
34
35
 
35
36
  def rel_for(sheet_name)
36
- Bmg.excel(@path, { sheet: sheet_name.to_s })
37
+ Bmg.excel(@path, @options[:reader_options].merge({
38
+ sheet: sheet_name.to_s
39
+ }))
37
40
  end
38
41
 
39
42
  end # class Sequel
data/lib/bmg/database.rb CHANGED
@@ -24,6 +24,7 @@ module Bmg
24
24
  end
25
25
 
26
26
  def to_data_folder(*args)
27
+ require_relative 'database/data_folder'
27
28
  DataFolder.dump(self, *args)
28
29
  end
29
30
 
@@ -31,5 +32,9 @@ module Bmg
31
32
  raise NotImplementedError
32
33
  end
33
34
 
35
+ def output_preferences_for(name)
36
+ nil
37
+ end
38
+
34
39
  end # class Database
35
40
  end # module Bmg
@@ -6,7 +6,8 @@ module Bmg
6
6
  DEFAULT_OPTIONS = {
7
7
  sheet: 0,
8
8
  skip: 0,
9
- row_num: true
9
+ row_num: true,
10
+ grouping_character: nil,
10
11
  }
11
12
 
12
13
  def initialize(type, path, options = {})
@@ -23,13 +24,16 @@ module Bmg
23
24
  headers = headers[1..-1] if generate_row_num?
24
25
  start_at = @options[:skip] + 2
25
26
  end_at = spreadsheet.last_row
27
+
28
+ previous = {}
26
29
  (start_at..end_at).each do |i|
27
30
  row = spreadsheet.row(i)
28
31
  init = init_tuple(i - start_at + 1)
29
32
  tuple = (0...headers.size).each_with_object(init){|i,t|
30
- t[headers[i]] = row[i]
33
+ t[headers[i]] = extract_value(headers[i], row[i], previous)
31
34
  }
32
35
  yield(tuple)
36
+ previous = tuple
33
37
  end
34
38
  end
35
39
 
@@ -75,6 +79,12 @@ module Bmg
75
79
  { row_num_name => i }
76
80
  end
77
81
 
82
+ def extract_value(attribute, value, previous)
83
+ return value unless c = @options[:grouping_character]
84
+
85
+ value == c ? previous[attribute] : value
86
+ end
87
+
78
88
  end # class Excel
79
89
  end # module Reader
80
90
  end # module Bmg
@@ -4,6 +4,7 @@ module Bmg
4
4
  DEFAULT_PREFS = {
5
5
  attributes_ordering: nil,
6
6
  tuple_ordering: nil,
7
+ grouping_attributes: nil,
7
8
  extra_attributes: :after
8
9
  }
9
10
 
@@ -36,14 +37,20 @@ module Bmg
36
37
  options[:grouping_attributes]
37
38
  end
38
39
 
40
+ def grouping_character
41
+ options[:grouping_character]
42
+ end
43
+
39
44
  def erase_redundance_in_group(before, current)
40
45
  return [nil, current] unless ga = grouping_attributes
41
46
  return [current, current] unless before
42
47
 
43
48
  new_before, new_current = current.dup, current.dup
44
49
  ga.each do |attr|
45
- return [new_before, new_current] unless before[attr] == current[attr]
46
- new_current[attr] = nil
50
+ unless before[attr] == current[attr]
51
+ return [new_before, new_current]
52
+ end
53
+ new_current[attr] = grouping_character
47
54
  end
48
55
  [new_before, new_current]
49
56
  end
data/lib/bmg/version.rb CHANGED
@@ -2,7 +2,7 @@ module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 23
5
- TINY = 5
5
+ TINY = 6
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
@@ -25,7 +25,7 @@ module Bmg
25
25
  rel.to_xlsx({
26
26
  workbook: workbook,
27
27
  worksheet: worksheet,
28
- })
28
+ }, nil, database.output_preferences_for(name))
29
29
  end
30
30
  workbook.close
31
31
  end
@@ -39,31 +39,48 @@ module Bmg
39
39
  @worksheet = workbook.add_worksheet(@worksheet) if @worksheet.is_a?(String)
40
40
 
41
41
  headers = infer_headers(relation.type)
42
+ max_widths = Hash.new{|h,k| h[k] = 5 }
42
43
  before = nil
44
+
45
+ write_headers(headers, worksheet, max_widths) unless headers.nil?
46
+
43
47
  each_tuple(relation) do |tuple,i|
44
- headers = infer_headers(tuple) if headers.nil?
45
- headers.each_with_index do |h,i|
46
- worksheet.write_string(0, i, h)
47
- end if i == 0
48
+ if headers.nil?
49
+ headers = infer_headers(tuple)
50
+ write_headers(headers, worksheet, max_widths)
51
+ end
48
52
  before, tuple = output_preferences.erase_redundance_in_group(before, tuple)
49
53
  headers.each_with_index do |h,j|
50
- meth, *args = write_pair(tuple[h])
54
+ meth, args, approx_width = write_pair(tuple[h])
51
55
  worksheet.send(meth, 1+i, j, *args)
56
+ max_widths[j] = [max_widths[j], approx_width].max
52
57
  end
53
58
  end
54
59
 
60
+ max_widths.each_pair do |col, width|
61
+ worksheet.set_column(col, col, [1+width, 100].min)
62
+ end
63
+ worksheet.freeze_panes(1, 0)
55
64
  workbook.close unless xlsx_options[:workbook]
56
65
  path
57
66
  end
58
67
 
68
+ def write_headers(headers, worksheet, max_widths)
69
+ header_format = workbook.add_format(bold: true)
70
+ headers.each_with_index do |h,i|
71
+ worksheet.write_string(0, i, h, header_format)
72
+ max_widths[i] = [max_widths[i], h.to_s.size].max
73
+ end
74
+ end
75
+
59
76
  def write_pair(value)
60
77
  case value
61
78
  when Numeric
62
- [:write_number, value]
79
+ [:write_number, [value], value.to_s.size]
63
80
  when Date
64
- [:write_date_time, value, date_format]
81
+ [:write_date_time, [value, date_format], value.to_s.size]
65
82
  else
66
- [:write_string, value.to_s]
83
+ [:write_string, [value.to_s], value.to_s.size]
67
84
  end
68
85
  end
69
86
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bmg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.5
4
+ version: 0.23.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-29 00:00:00.000000000 Z
11
+ date: 2025-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: predicate
@@ -347,7 +347,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
347
347
  - !ruby/object:Gem::Version
348
348
  version: '0'
349
349
  requirements: []
350
- rubygems_version: 3.3.27
350
+ rubygems_version: 3.4.19
351
351
  signing_key:
352
352
  specification_version: 4
353
353
  summary: Bmg is Alf's successor.