onoma 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitlab-ci.yml +14 -0
  4. data/Gemfile +2 -0
  5. data/Rakefile +3 -6
  6. data/bin/rake +29 -0
  7. data/config/locales/eng.yml +1 -9
  8. data/config/locales/fra.yml +49 -165
  9. data/db/migrate/20190807125202_add_nature_to_product_natures.xml +326 -0
  10. data/db/migrate/20190909150402_add_staff_supply_stock_account.xml +4 -0
  11. data/db/migrate/20190913102036_add_caliber_indicator.xml +4 -0
  12. data/db/migrate/20191016152118_add_missing_document_templates.xml +6 -0
  13. data/db/migrate/20191113134626_add_nature_to_new_product_natures.xml +11 -0
  14. data/db/migrate/20191125133327_add_missing_units_and_indicators.xml +5 -0
  15. data/db/migrate/20200107095554_add_signed_field_to_document_nature.xml +9 -0
  16. data/db/migrate/20200421123503_add_type_to_categories_and_variants.xml +1136 -0
  17. data/db/migrate/20200514092205_add_liter_per_hectoliter_unit.xml +4 -0
  18. data/db/migrate/20200722091859_triticale_derivative_of.xml +5 -0
  19. data/db/reference.xml +948 -944
  20. data/lib/onoma.rb +82 -24
  21. data/lib/onoma/item.rb +19 -3
  22. data/lib/onoma/migration/actions/base.rb +1 -5
  23. data/lib/onoma/migration/actions/item_change.rb +1 -5
  24. data/lib/onoma/migration/actions/item_creation.rb +2 -6
  25. data/lib/onoma/migration/actions/item_merging.rb +1 -5
  26. data/lib/onoma/migration/actions/item_removal.rb +1 -1
  27. data/lib/onoma/migration/actions/nomenclature_change.rb +1 -1
  28. data/lib/onoma/migration/actions/nomenclature_creation.rb +1 -1
  29. data/lib/onoma/migration/actions/nomenclature_removal.rb +1 -5
  30. data/lib/onoma/migration/actions/property_creation.rb +4 -4
  31. data/lib/onoma/migration/base.rb +38 -0
  32. data/lib/onoma/migrator.rb +13 -0
  33. data/lib/onoma/migrator/reference.rb +71 -0
  34. data/lib/onoma/migrator/translation.rb +76 -0
  35. data/lib/onoma/models/ability.rb +4 -0
  36. data/lib/onoma/models/account.rb +4 -0
  37. data/lib/onoma/models/accounting_system.rb +12 -0
  38. data/lib/onoma/models/activity_family.rb +4 -0
  39. data/lib/onoma/models/administrative_area.rb +4 -0
  40. data/lib/onoma/models/administrative_area_nature.rb +4 -0
  41. data/lib/onoma/models/analysis_nature.rb +4 -0
  42. data/lib/onoma/models/animal_life_state.rb +4 -0
  43. data/lib/onoma/models/cation_exchange_capacity_analysis_method.rb +4 -0
  44. data/lib/onoma/models/certification.rb +4 -0
  45. data/lib/onoma/models/certification_label.rb +4 -0
  46. data/lib/onoma/models/chemical_classification.rb +4 -0
  47. data/lib/onoma/models/chemical_element.rb +4 -0
  48. data/lib/onoma/models/country.rb +4 -0
  49. data/lib/onoma/models/crop_set.rb +4 -0
  50. data/lib/onoma/models/currency.rb +4 -0
  51. data/lib/onoma/models/delivery_mode.rb +4 -0
  52. data/lib/onoma/models/dimension.rb +4 -0
  53. data/lib/onoma/models/document_category.rb +4 -0
  54. data/lib/onoma/models/document_nature.rb +4 -0
  55. data/lib/onoma/models/entity_link_nature.rb +4 -0
  56. data/lib/onoma/models/event_nature.rb +4 -0
  57. data/lib/onoma/models/fence_perimeter.rb +4 -0
  58. data/lib/onoma/models/figure.rb +4 -0
  59. data/lib/onoma/models/fiscal_position.rb +4 -0
  60. data/lib/onoma/models/guide_nature.rb +4 -0
  61. data/lib/onoma/models/identifier_nature.rb +4 -0
  62. data/lib/onoma/models/indicator.rb +7 -0
  63. data/lib/onoma/models/issue_nature.rb +4 -0
  64. data/lib/onoma/models/land.rb +4 -0
  65. data/lib/onoma/models/language.rb +4 -0
  66. data/lib/onoma/models/mammalia_birth_condition.rb +4 -0
  67. data/lib/onoma/models/mammalia_reproduction_state.rb +4 -0
  68. data/lib/onoma/models/molecule.rb +4 -0
  69. data/lib/onoma/models/net_service.rb +4 -0
  70. data/lib/onoma/models/opportunity_origin.rb +4 -0
  71. data/lib/onoma/models/phosphorus_analysis_method.rb +4 -0
  72. data/lib/onoma/models/plant_life_state.rb +4 -0
  73. data/lib/onoma/models/plant_reproduction_state.rb +4 -0
  74. data/lib/onoma/models/plants_growth_level.rb +4 -0
  75. data/lib/onoma/models/procedure_action.rb +4 -0
  76. data/lib/onoma/models/procedure_category.rb +4 -0
  77. data/lib/onoma/models/procedure_nature.rb +4 -0
  78. data/lib/onoma/models/procedure_role.rb +4 -0
  79. data/lib/onoma/models/product_nature.rb +4 -0
  80. data/lib/onoma/models/product_nature_category.rb +4 -0
  81. data/lib/onoma/models/product_nature_variant.rb +4 -0
  82. data/lib/onoma/models/production_nature.rb +4 -0
  83. data/lib/onoma/models/production_system.rb +4 -0
  84. data/lib/onoma/models/production_usage.rb +4 -0
  85. data/lib/onoma/models/residue_elimination_method.rb +4 -0
  86. data/lib/onoma/models/role.rb +4 -0
  87. data/lib/onoma/models/running_cost.rb +4 -0
  88. data/lib/onoma/models/sex.rb +4 -0
  89. data/lib/onoma/models/soil_cultural_state.rb +4 -0
  90. data/lib/onoma/models/soil_nature.rb +4 -0
  91. data/lib/onoma/models/spatial_reference_system.rb +4 -0
  92. data/lib/onoma/models/tax.rb +4 -0
  93. data/lib/onoma/models/tax_nature.rb +4 -0
  94. data/lib/onoma/models/unit.rb +4 -0
  95. data/lib/onoma/models/variety.rb +31 -0
  96. data/lib/onoma/models/working_set.rb +4 -0
  97. data/lib/onoma/nomenclature.rb +19 -23
  98. data/lib/onoma/{database.rb → nomenclature_set.rb} +25 -57
  99. data/lib/onoma/{property.rb → property_nature.rb} +5 -8
  100. data/lib/onoma/record/base.rb +15 -0
  101. data/lib/onoma/reflection.rb +3 -3
  102. data/lib/onoma/version.rb +4 -2
  103. data/onoma.gemspec +16 -17
  104. metadata +100 -23
  105. data/lib/onoma/migration.rb +0 -122
  106. data/lib/onoma/migration/actions.rb +0 -9
@@ -1,32 +1,48 @@
1
- require 'onoma/version'
1
+ require 'active_support/inflector'
2
+ require 'active_support/core_ext/object/blank'
3
+ require 'active_support/core_ext/array/access'
4
+ require 'active_support/core_ext/hash/keys'
5
+ require 'active_support/core_ext/hash/indifferent_access'
6
+ require 'bigdecimal'
7
+ require 'date'
8
+ require 'i18n'
2
9
  require 'nokogiri'
3
- require 'active_support/hash_with_indifferent_access'
4
-
5
- require 'onoma/item'
6
- require 'onoma/migration'
7
- require 'onoma/nomenclature'
8
- require 'onoma/database'
9
- require 'onoma/property'
10
- require 'onoma/reference'
11
- require 'onoma/relation'
12
- require 'onoma/reflection'
13
10
  require 'pathname'
11
+ require 'yaml'
12
+ require 'zeitwerk'
13
+
14
+ loader = Zeitwerk::Loader.for_gem
15
+ loader.collapse('lib/onoma/models')
16
+ loader.setup
14
17
 
15
18
  module Onoma
16
19
  XMLNS = 'http://www.ekylibre.org/XML/2013/nomenclatures'.freeze
17
20
  NS_SEPARATOR = '-'.freeze
18
21
  PROPERTY_TYPES = %i[boolean item item_list choice choice_list string_list date decimal integer nomenclature string symbol].freeze
19
22
 
20
- class MissingNomenclature < StandardError
23
+ class Error < ::StandardError
24
+ end
25
+
26
+ class MissingNomenclature < Error
27
+ end
28
+
29
+ class ItemNotFound < Error
30
+ end
31
+
32
+ class MissingChoices < Error
21
33
  end
22
34
 
23
- class MissingChoices < StandardError
35
+ class InvalidPropertyNature < Error
24
36
  end
25
37
 
26
- class InvalidProperty < StandardError
38
+ class InvalidProperty < Error
27
39
  end
28
40
 
29
41
  class << self
42
+ def escape_key(key)
43
+ key.to_s.gsub('.', '-').to_sym
44
+ end
45
+
30
46
  def root
31
47
  Pathname.new(__FILE__).dirname.dirname
32
48
  end
@@ -43,9 +59,36 @@ module Onoma
43
59
  database_path.join('reference.xml')
44
60
  end
45
61
 
46
- def connection
47
- load_database unless database_loaded?
48
- @@set
62
+ # Returns version of DB
63
+ def reference_version
64
+ return 0 unless reference_path.exist?
65
+ reference_document.root['version'].to_i
66
+ end
67
+
68
+ def reference_document
69
+ unless @document
70
+ f = File.open(reference_path, 'rb')
71
+ @document = Nokogiri::XML(f) do |config|
72
+ config.strict.nonet.noblanks.noent
73
+ end
74
+ f.close
75
+ end
76
+ @document
77
+ end
78
+
79
+ # Returns list of Onoma::Migration
80
+ def migrations
81
+ Dir.glob(migrations_path.join('*.xml')).sort.collect do |f|
82
+ Onoma::Migration::Base.parse(Pathname.new(f))
83
+ end
84
+ end
85
+
86
+ # Returns list of migrations since last done
87
+ def missing_migrations
88
+ last_version = reference_version
89
+ migrations.select do |m|
90
+ m.number > last_version
91
+ end
49
92
  end
50
93
 
51
94
  # Returns the names of the nomenclatures
@@ -53,34 +96,49 @@ module Onoma
53
96
  set.nomenclature_names
54
97
  end
55
98
 
99
+ def all
100
+ set.nomenclatures
101
+ end
102
+
56
103
  # Give access to named nomenclatures
57
- delegate :[], :nomenclatures, to: :set
58
- alias all nomenclatures
104
+ # delegate :[], to: :set
105
+ def [](index)
106
+ set[index]
107
+ end
59
108
 
60
109
  # Give access to named nomenclatures
61
110
  def find(*args)
62
111
  args.extract_options!
63
112
  name = args.shift
113
+ nomenclature = find_or_initialize(name)
64
114
  if args.empty?
65
- return set[name]
115
+ return nomenclature
66
116
  elsif args.size == 1
67
- return set[name].find(args.shift) if set[name]
117
+ return nomenclature.find(args.shift) if nomenclature
68
118
  end
69
119
  nil
70
120
  end
71
121
 
122
+ def find_or_initialize(name)
123
+ set[name] || set.load_data_from_xml(name)
124
+ end
125
+
126
+ # Force loading of nomenclatures
127
+ def load!
128
+ @@set = NomenclatureSet.load_file(reference_path)
129
+ end
130
+
72
131
  # Browse all nomenclatures
73
132
  def each(&block)
74
133
  set.each(&block)
75
134
  end
76
135
 
77
136
  def set
78
- @@set ||= Database.open(reference_path)
137
+ @@set ||= NomenclatureSet.new
79
138
  end
80
139
 
81
140
  def load_locales
82
- I18n.load_path.concat(Dir.glob(root.join('config', 'locales', '**', '*.yml')))
141
+ I18n.load_path.concat(Dir.glob(Onoma.root.join('config', 'locales', '*.yml')))
83
142
  end
84
143
  end
85
144
  end
86
-
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  module Onoma
2
4
  # An item of a nomenclature is the core data.
3
5
  class Item
@@ -19,7 +21,7 @@ module Onoma
19
21
  else
20
22
  self.parent = parent
21
23
  end
22
- @attributes = ActiveSupport::HashWithIndifferentAccess.new
24
+ @attributes = {}.with_indifferent_access
23
25
  @children = Set.new
24
26
  options.each do |k, v|
25
27
  set(k, v)
@@ -178,14 +180,28 @@ module Onoma
178
180
 
179
181
  # Return human name of item
180
182
  def human_name(options = {})
181
- I18n.translate("nomenclatures.#{nomenclature.name}.items.#{name}", options.merge(default: ["items.#{name}".to_sym, "enumerize.#{nomenclature.name}.#{name}".to_sym, "labels.#{name}".to_sym, name.humanize]))
183
+ scope = options.delete(:scope)
184
+ no_attribute_translation = "nomenclatures.#{Onoma.escape_key(nomenclature.name)}.items.#{Onoma.escape_key(name)}"
185
+ if scope
186
+ scope_attribute = scope
187
+ other_attributes = attributes.except(scope_attribute)
188
+ scope_translation = "nomenclatures.#{Onoma.escape_key(nomenclature.name)}.items.#{Onoma.escape_key(scope_attribute)}.#{Onoma.escape_key(name)}"
189
+ other_translations = other_attributes.map { |attr_name, _value| "nomenclatures.#{Onoma.escape_key(nomenclature.name)}.items.#{Onoma.escape_key(attr_name)}.#{Onoma.escape_key(name)}" }
190
+ root = scope_translation
191
+ defaults = [no_attribute_translation, *other_translations]
192
+ else
193
+ scoped_by_attributes = attributes.map { |attr_name, _value| "nomenclatures.#{Onoma.escape_key(nomenclature.name)}.items.#{Onoma.escape_key(attr_name)}.#{Onoma.escape_key(name)}" }
194
+ root = "nomenclatures.#{Onoma.escape_key(nomenclature.name)}.items.#{Onoma.escape_key(name)}"
195
+ defaults = scoped_by_attributes
196
+ end
197
+ I18n.t(root, options.merge(default: [*defaults.map(&:to_sym), "items.#{Onoma.escape_key(name)}".to_sym, "enumerize.#{Onoma.escape_key(nomenclature.name)}.#{Onoma.escape_key(name)}".to_sym, "labels.#{Onoma.escape_key(name)}".to_sym, name.humanize]))
182
198
  end
183
199
  alias humanize human_name
184
200
  alias localize human_name
185
201
  alias l localize
186
202
 
187
203
  def human_notion_name(notion_name, options = {})
188
- "nomenclatures.#{nomenclature.name}.notions.#{notion_name}.#{name}".t(options.merge(default: ["labels.#{name}".to_sym]))
204
+ I18n.t("nomenclatures.#{nomenclature.name}.notions.#{notion_name}.#{name}", options.merge(default: ["labels.#{name}".to_sym]))
189
205
  end
190
206
 
191
207
  def ==(other)
@@ -1,5 +1,5 @@
1
1
  module Onoma
2
- class Migration
2
+ module Migration
3
3
  module Actions
4
4
  class Base
5
5
  def self.action_name
@@ -9,10 +9,6 @@ module Onoma
9
9
  def action_name
10
10
  self.class.action_name
11
11
  end
12
-
13
- def label
14
- action_name
15
- end
16
12
  end
17
13
  end
18
14
  end
@@ -1,5 +1,5 @@
1
1
  module Onoma
2
- class Migration
2
+ module Migration
3
3
  module Actions
4
4
  class ItemChange < Onoma::Migration::Actions::Base
5
5
  attr_reader :nomenclature, :name, :changes
@@ -22,10 +22,6 @@ module Onoma
22
22
  @changes[:name]
23
23
  end
24
24
 
25
- def label
26
- "change_item #{@nomenclature}##{@name}(" + changes.simple_print + ')'
27
- end
28
-
29
25
  def human_name
30
26
  "Change item #{@nomenclature}##{@name} with " + changes.inspect
31
27
  end
@@ -1,5 +1,5 @@
1
1
  module Onoma
2
- class Migration
2
+ module Migration
3
3
  module Actions
4
4
  class ItemCreation < Onoma::Migration::Actions::Base
5
5
  attr_reader :nomenclature, :name, :options
@@ -20,10 +20,6 @@ module Onoma
20
20
  @options.any?
21
21
  end
22
22
 
23
- def label
24
- "create_item #{@nomenclature}##{@name}" + (@options.any? ? "(#{@options.simple_print})" : '')
25
- end
26
-
27
23
  def human_name
28
24
  updates = []
29
25
  updates << "#{@name} as name"
@@ -31,7 +27,7 @@ module Onoma
31
27
  @options.each do |k, v|
32
28
  updates << "#{v} as #{k}"
33
29
  end
34
- "Create item #{@nomenclature}##{@name} with " + updates.to_sentence
30
+ sentence = "Create item #{@nomenclature}##{@name} with " + updates.to_sentence
35
31
  end
36
32
  end
37
33
  end
@@ -1,5 +1,5 @@
1
1
  module Onoma
2
- class Migration
2
+ module Migration
3
3
  module Actions
4
4
  class ItemMerging < Onoma::Migration::Actions::Base
5
5
  attr_reader :nomenclature, :name, :into
@@ -10,10 +10,6 @@ module Onoma
10
10
  @into = element['into'].to_s
11
11
  end
12
12
 
13
- def label
14
- "merge_item #{@nomenclature}##{@name} into " + @into.to_s
15
- end
16
-
17
13
  def human_name
18
14
  "Merge item #{@nomenclature}##{@name} into #{@into}"
19
15
  end
@@ -1,5 +1,5 @@
1
1
  module Onoma
2
- class Migration
2
+ module Migration
3
3
  module Actions
4
4
  class ItemRemoval < Onoma::Migration::Actions::Base
5
5
  attr_reader :nomenclature, :name
@@ -1,5 +1,5 @@
1
1
  module Onoma
2
- class Migration
2
+ module Migration
3
3
  module Actions
4
4
  class NomenclatureChange < Onoma::Migration::Actions::Base
5
5
  attr_reader :nomenclature, :changes
@@ -1,5 +1,5 @@
1
1
  module Onoma
2
- class Migration
2
+ module Migration
3
3
  module Actions
4
4
  class NomenclatureCreation < Onoma::Migration::Actions::Base
5
5
  attr_reader :nomenclature, :options
@@ -1,5 +1,5 @@
1
1
  module Onoma
2
- class Migration
2
+ module Migration
3
3
  module Actions
4
4
  class NomenclatureRemoval < Onoma::Migration::Actions::Base
5
5
  attr_reader :nomenclature
@@ -11,10 +11,6 @@ module Onoma
11
11
 
12
12
  alias name nomenclature
13
13
 
14
- def label
15
- "remove_nomenclature #{@name}"
16
- end
17
-
18
14
  def human_name
19
15
  "Remove nomenclature #{@name}"
20
16
  end
@@ -1,5 +1,5 @@
1
1
  module Onoma
2
- class Migration
2
+ module Migration
3
3
  module Actions
4
4
  class PropertyCreation < Onoma::Migration::Actions::Base
5
5
  attr_reader :nomenclature, :name, :type, :options
@@ -8,7 +8,7 @@ module Onoma
8
8
  @nomenclature = name.first
9
9
  @name = name.second
10
10
  @type = element['type'].to_sym
11
- unless Property::TYPES.include?(@type)
11
+ unless Onoma::PROPERTY_TYPES.include?(@type)
12
12
  raise ArgumentError, "Property #{name} type is unknown: #{@type.inspect}"
13
13
  end
14
14
  @options = {}
@@ -18,7 +18,7 @@ module Onoma
18
18
  if element.has_attribute?('default')
19
19
  @options[:default] = element.attr('default').to_sym
20
20
  end
21
- @options[:required] = !!(element.attr('required').to_s == 'true')
21
+ @options[:required] = element.attr('required').to_s == 'true'
22
22
  # @options[:inherit] = !!(element.attr('inherit').to_s == 'true')
23
23
  if element.has_attribute?('choices')
24
24
  if type == :choice || type == :choice_list
@@ -35,7 +35,7 @@ module Onoma
35
35
  @options.each do |k, v|
36
36
  updates << "#{v} as #{k}"
37
37
  end
38
- "Create property #{@nomenclature}.#{@name} with " + updates.to_sentence
38
+ sentence = "Create property #{@nomenclature}.#{@name} with " + updates.to_sentence
39
39
  end
40
40
  end
41
41
  end
@@ -0,0 +1,38 @@
1
+ module Onoma
2
+ module Migration
3
+ class Base
4
+ def self.parse(file)
5
+ f = File.open(file, 'rb')
6
+ document = Nokogiri::XML(f) do |config|
7
+ config.strict.nonet.noblanks.noent
8
+ end
9
+ f.close
10
+ root = document.root
11
+ number = file.basename.to_s.split('_').first.to_i
12
+ new(number, root['name'], root)
13
+ end
14
+
15
+ attr_reader :number, :name
16
+
17
+ def initialize(number, name, element = nil)
18
+ @number = number
19
+ @name = name
20
+ @actions = []
21
+ if element
22
+ element.children.each do |child|
23
+ next unless child.is_a? Nokogiri::XML::Element
24
+ @actions << "Onoma::Migration::Actions::#{child.name.underscore.classify}".constantize.new(child)
25
+ end
26
+ end
27
+ end
28
+
29
+ def each_action(&block)
30
+ @actions.each(&block)
31
+ end
32
+
33
+ def inspect
34
+ "#<#{self.class.name}:#{format('%#x', object_id)} ##{number} #{name.inspect} (#{@actions.size} actions)>"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ module Onoma
2
+ module Migrator
3
+ class << self
4
+ def migrate
5
+ Onoma.missing_migrations.each do |migration|
6
+ puts migration.name
7
+ Onoma::Migrator::Reference.run(migration)
8
+ Onoma::Migrator::Translation.run(migration)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,71 @@
1
+ module Onoma
2
+ module Migrator
3
+ class Reference
4
+ def self.run(migration)
5
+ ref = new
6
+ migration.each_action do |action|
7
+ ref.send(action.action_name, action)
8
+ end
9
+ ref.version = migration.number
10
+ puts "Write DB in #{Onoma.reference_path.relative_path_from(Onoma.root)}"
11
+ ref.write
12
+ end
13
+
14
+ def initialize
15
+ @set = if Onoma.reference_path.exist?
16
+ Onoma::NomenclatureSet.load_file(Onoma.reference_path)
17
+ else
18
+ Onoma::NomenclatureSet.new
19
+ end
20
+ end
21
+
22
+ def version
23
+ @set.version
24
+ end
25
+
26
+ def version=(number)
27
+ @set.version = number
28
+ end
29
+
30
+ def write
31
+ File.write(Onoma.reference_path, @set.to_xml)
32
+ end
33
+
34
+ def nomenclature_creation(action)
35
+ @set.add_nomenclature(action.name, action.options)
36
+ end
37
+
38
+ def nomenclature_change(action)
39
+ @set.change_nomenclature(action.nomenclature, action.changes)
40
+ end
41
+
42
+ def nomenclature_removal(action)
43
+ @set.remove_nomenclature(action.nomenclature)
44
+ end
45
+
46
+ def property_creation(action)
47
+ @set.add_property(action.nomenclature, action.name, action.type, action.options)
48
+ end
49
+
50
+ def property_change(action)
51
+ @set.add_property(action.nomenclature, action.name, action.changes)
52
+ end
53
+
54
+ def item_creation(action)
55
+ @set.add_item(action.nomenclature, action.name, action.options)
56
+ end
57
+
58
+ def item_change(action)
59
+ @set.change_item(action.nomenclature, action.name, action.changes)
60
+ end
61
+
62
+ def item_merging(action)
63
+ @set.merge_item(action.nomenclature, action.name, action.into)
64
+ end
65
+
66
+ def item_removal(action)
67
+ @set.remove_item(action.nomenclature, action.name)
68
+ end
69
+ end
70
+ end
71
+ end