apidae 0.10.0 → 1.0.4

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.
@@ -14,41 +14,49 @@ module Apidae
14
14
  store_accessor :pictures_data, :pictures
15
15
  store_accessor :attachments_data, :attachments
16
16
  store_accessor :type_data, :categories, :themes, :capacity, :classification, :labels, :chains, :area, :track,
17
- :products, :audience, :animals, :extra, :duration, :certifications, :business
17
+ :products, :audience, :animals, :animals_desc, :extra, :duration, :certifications, :business
18
18
  store_accessor :entity_data, :entity_id, :entity_name, :service_provider_id
19
- store_accessor :contact, :telephone, :email, :website
19
+ store_accessor :contact_data, :telephone, :email, :website, :google, :facebook, :twitter, :yelp, :trip_advisor, :contacts
20
20
  store_accessor :location_data, :address, :place, :latitude, :longitude, :access, :territories, :environments
21
- store_accessor :openings_data, :openings_desc, :openings_desc_mode, :openings, :time_periods
21
+ store_accessor :openings_data, :openings_desc, :openings_desc_mode, :openings, :time_periods, :openings_extra
22
22
  store_accessor :rates_data, :rates_desc, :rates_desc_mode, :rates, :payment_methods, :includes, :excludes
23
23
  store_accessor :service_data, :services, :equipments, :comfort, :activities, :challenged, :languages
24
24
  store_accessor :booking_data, :booking_desc, :booking_entities
25
25
  store_accessor :tags_data, :promo, :internal, :linked
26
26
  store_accessor :version_data, :versioned_fields
27
27
 
28
- LOCALIZED_FIELDS.each do |f|
29
- alias_method :"#{f}_hash", :"#{f}"
30
- alias_method :"#{f}_hash=", :"#{f}="
28
+ ALL_FIELDS.each do |f|
29
+ alias_method :"get_#{f}", :"#{f}"
30
+ alias_method :"set_#{f}", :"#{f}="
31
31
 
32
- define_method "#{f}=" do |val|
33
- ref_obj = (@obj_version == DEFAULT_VERSION || @obj_version.nil?) ? self : in_version(@obj_version)
34
- field_hash = ref_obj.send(:"#{f}_hash") || {}
35
- ref_obj.send(:"#{f}_hash=", field_hash.merge(@locale => val))
32
+ if LOCALIZED_FIELDS.include?(f)
33
+ define_method "#{f}=" do |val|
34
+ ref_obj = (@obj_version == DEFAULT_VERSION || @obj_version.nil?) ? self : in_version(@obj_version)
35
+ current_val = ref_obj.send(:"get_#{f}") || {}
36
+ ref_obj.send(:"set_#{f}", current_val.merge(@locale => val))
37
+ end
38
+ else
39
+ define_method "#{f}=" do |val|
40
+ ref_obj = (@obj_version == DEFAULT_VERSION || @obj_version.nil?) ? self : in_version(@obj_version)
41
+ ref_obj.send(:"set_#{f}", val)
42
+ end
36
43
  end
37
44
 
38
45
  define_method f do
39
- field_hash = self.send(:"#{f}_hash") || {}
46
+ default_value = LOCALIZED_FIELDS.include?(f) ? {} : nil
47
+ field_val = self.send(:"get_#{f}") || default_value
40
48
  unless @obj_version == DEFAULT_VERSION
41
49
  versioned_obj = in_version(@obj_version)
42
50
  if versioned_obj
43
- versioned_hash = versioned_obj.send(:"#{f}_hash") || {}
51
+ versioned_value = versioned_obj.send(:"get_#{f}") || default_value
44
52
  if versioned_obj.versioned_fields.include?(f.to_s)
45
- field_hash = versioned_hash
46
- else
47
- field_hash.deep_merge!(versioned_hash)
53
+ field_val = versioned_value
54
+ elsif field_val.respond_to?('deep_merge!')
55
+ field_val.deep_merge!(versioned_value)
48
56
  end
49
57
  end
50
58
  end
51
- field_hash[@locale] || field_hash[DEFAULT_LOCALE]
59
+ LOCALIZED_FIELDS.include?(f) ? (field_val[@locale] || field_val[DEFAULT_LOCALE]) : field_val
52
60
  end
53
61
  end
54
62
 
@@ -88,13 +96,6 @@ module Apidae
88
96
  TER => {node: :informationsTerritoire, subtype: :territoireType}
89
97
  }
90
98
 
91
- PHONE = 201
92
- EMAIL = 204
93
- WEBSITE = 205
94
-
95
- MODE_AUTO = 'auto'
96
- MODE_MANUAL = 'manual'
97
-
98
99
  after_initialize do
99
100
  @locale = DEFAULT_LOCALE
100
101
  @obj_version = DEFAULT_VERSION
@@ -121,6 +122,18 @@ module Apidae
121
122
  self
122
123
  end
123
124
 
125
+ def dig(*keys)
126
+ root_key, *nested_keys = keys
127
+ root_val = self.send(root_key)
128
+ if root_val.blank?
129
+ nested_keys.blank? ? root_val : nil
130
+ elsif root_val.respond_to?(:dig)
131
+ root_val.dig(*nested_keys)
132
+ else
133
+ raise ArgumentError.new('Cannot call dig with these args')
134
+ end
135
+ end
136
+
124
137
  def self.default_scope
125
138
  where(root_obj_id: nil)
126
139
  end
@@ -141,7 +154,7 @@ module Apidae
141
154
  version_data[:type] = apidae_obj.apidae_type
142
155
  version_obj = apidae_obj.in_version(version) || Obj.new(apidae_id: apidae_obj.apidae_id,
143
156
  root_obj_id: apidae_obj.id, version: version)
144
- version_obj.versioned_fields = parse_versioned_fields(version_data)
157
+ version_obj.versioned_fields = ApidaeDataParser.parse_versioned_fields(version_data)
145
158
  populate_fields(version_obj, version_data, locales)
146
159
  version_obj.save!
147
160
  end
@@ -153,299 +166,31 @@ module Apidae
153
166
  def self.populate_fields(apidae_obj, object_data, locales)
154
167
  type_fields = TYPES_DATA[object_data[:type]]
155
168
  apidae_obj.last_update = DateTime.parse(object_data[:gestion][:dateModification]) unless object_data[:gestion].blank?
156
- apidae_obj.owner_data = parse_owner_data(object_data[:gestion][:membreProprietaire]) unless object_data[:gestion].blank?
169
+ apidae_obj.owner_data = ApidaeDataParser.parse_owner_data(object_data[:gestion][:membreProprietaire]) unless object_data[:gestion].blank?
157
170
  apidae_obj.apidae_type = object_data[:type]
158
- apidae_obj.apidae_subtype = node_id(object_data[type_fields[:node]], type_fields[:subtype])
159
- apidae_obj.title_data = parse_title(object_data, *locales)
160
- apidae_obj.description_data = parse_desc_data(object_data[:presentation], object_data[:donneesPrivees], *locales)
161
- apidae_obj.contact = contact(object_data[:informations])
162
- apidae_obj.location_data = parse_location_data(object_data[:localisation], object_data[type_fields[:node]],
171
+ apidae_obj.apidae_subtype = ApidaeDataParser.node_id(object_data[type_fields[:node]], type_fields[:subtype])
172
+ apidae_obj.title_data = ApidaeDataParser.parse_title(object_data, *locales)
173
+ apidae_obj.description_data = ApidaeDataParser.parse_desc_data(object_data[:presentation], object_data[:donneesPrivees], *locales)
174
+ apidae_obj.contact_data = ApidaeDataParser.parse_contact_data(object_data[:informations], object_data[:contacts])
175
+ apidae_obj.location_data = ApidaeDataParser.parse_location_data(object_data[:localisation], object_data[type_fields[:node]],
163
176
  object_data[:territoires])
164
- apidae_obj.town = town(object_data[:localisation])
165
- apidae_obj.openings_data = parse_openings(object_data[:ouverture], *locales)
166
- apidae_obj.rates_data = parse_rates(object_data[:descriptionTarif], *locales)
167
- apidae_obj.booking_data = parse_booking(object_data[:reservation], *locales)
168
- apidae_obj.type_data = parse_type_data(apidae_obj, object_data[type_fields[:node]], object_data[:prestations],
177
+ apidae_obj.town = ApidaeDataParser.parse_town(object_data[:localisation])
178
+ apidae_obj.openings_data = ApidaeDataParser.parse_openings(object_data[:ouverture], *locales)
179
+ apidae_obj.rates_data = ApidaeDataParser.parse_rates(object_data[:descriptionTarif], *locales)
180
+ apidae_obj.booking_data = ApidaeDataParser.parse_booking(object_data[:reservation], *locales)
181
+ apidae_obj.type_data = ApidaeDataParser.parse_type_data(apidae_obj, object_data[type_fields[:node]], object_data[:prestations],
169
182
  object_data[:tourismeAffaires], *locales)
170
- apidae_obj.pictures_data = parse_pictures_data(object_data[:illustrations], *locales)
171
- apidae_obj.attachments_data = parse_attachments_data(object_data[:multimedias], *locales)
172
- apidae_obj.entity_data = entity_fields(object_data[:informations], object_data[type_fields[:node]])
173
- apidae_obj.service_data = parse_service_data(object_data[:prestations], object_data[type_fields[:node]])
174
- apidae_obj.tags_data = parse_tags_data(object_data[:presentation], object_data[:criteresInternes], object_data[:liens])
183
+ apidae_obj.pictures_data = ApidaeDataParser.parse_pictures_data(object_data[:illustrations], *locales)
184
+ apidae_obj.attachments_data = ApidaeDataParser.parse_attachments_data(object_data[:multimedias], *locales)
185
+ apidae_obj.entity_data = ApidaeDataParser.parse_entity_fields(object_data[:informations], object_data[type_fields[:node]])
186
+ apidae_obj.service_data = ApidaeDataParser.parse_service_data(object_data[:prestations], object_data[type_fields[:node]])
187
+ apidae_obj.tags_data = ApidaeDataParser.parse_tags_data(object_data[:presentation], object_data[:criteresInternes], object_data[:liens])
175
188
  apidae_obj.meta_data = object_data[:metadonnees]
176
189
  end
177
190
 
178
- def self.non_empty(data_hash)
179
- data_hash.keep_if {|k, v| !v.blank?}
180
- end
181
-
182
- def self.parse_versioned_fields(data_hash)
183
- version_fields = data_hash[:champsAspect] || []
184
- matched_fields = []
185
- version_fields.each do |f|
186
- case f
187
- when 'nom'
188
- matched_fields << 'title'
189
- when 'presentation.descriptifCourt'
190
- matched_fields << 'short_desc'
191
- when 'presentation.descriptifDetaille'
192
- matched_fields << 'long_desc'
193
- when 'illustrations'
194
- matched_fields << 'pictures'
195
- when 'multimedias'
196
- matched_fields << 'attachments'
197
- when 'informations.moyensCommunication'
198
- matched_fields << 'contact'
199
- when 'descriptifsThematises'
200
- matched_fields << 'theme_desc'
201
- when 'ouverture.periodesOuvertures', 'ouverture.periodeEnClair'
202
- matched_fields << 'openings_desc'
203
- matched_fields << 'openings'
204
- when 'ouverture.periodeEnClairAutomatique'
205
- matched_fields << 'openings_desc_mode'
206
- when 'descriptionTarif.tarifsEnClair', 'descriptionTarif.periodes'
207
- matched_fields << 'rates_desc'
208
- matched_fields << 'rates'
209
- when 'descriptionTarif.tarifsEnClairAutomatique'
210
- matched_fields << 'rates_desc_mode'
211
- when 'prestations.equipements'
212
- matched_fields << 'equipments'
213
- when 'prestations.activites'
214
- matched_fields << 'activities'
215
- when 'prestations.services'
216
- matched_fields << 'services'
217
- when 'localisation.environnements'
218
- matched_fields << 'environments'
219
- when 'prestations.complementAccueil'
220
- matched_fields << 'extra'
221
- when 'localisation.geolocalisation.complement'
222
- matched_fields << 'access'
223
- else
224
- end
225
- end
226
- matched_fields.uniq
227
- end
228
-
229
- def self.parse_title(data_hash, *locales)
230
- {title: node_value(data_hash, :nom, *locales)}
231
- end
232
-
233
- def self.parse_owner_data(data_hash)
234
- unless data_hash.blank?
235
- {owner_name: data_hash[:nom], owner_id: data_hash[:id]}
236
- end
237
- end
238
-
239
- def self.parse_desc_data(data_hash, private_data, *locales)
240
- unless data_hash.blank?
241
- {
242
- short_desc: node_value(data_hash, :descriptifCourt, *locales),
243
- long_desc: node_value(data_hash, :descriptifDetaille, *locales),
244
- theme_desc: data_hash[:descriptifsThematises].blank? ? {} : Hash[data_hash[:descriptifsThematises].map {|th| [node_id(th, :theme), node_value(th, :description, *locales)]}],
245
- private_desc: private_data.blank? ? {} : Hash[private_data.map {|d| [d[:nomTechnique], node_value(d, :descriptif, *locales)]}]
246
- }
247
- end
248
- end
249
-
250
- def self.parse_pictures_data(pictures_array, *locales)
251
- pics_data = {}
252
- unless pictures_array.blank?
253
- l = locales.blank? ? [DEFAULT_LOCALE] : locales
254
- l.each do |locale|
255
- pics_data[locale] = []
256
- pictures_array.select { |p| p.is_a?(Hash) && !p[:traductionFichiers].blank? }.each do |pic|
257
- pics_data[locale] << {
258
- id: pic[:identifiant],
259
- name: localized_value(pic, :nom, locale),
260
- url: pic[:traductionFichiers][0][:url].gsub('http:', 'https:'),
261
- description: localized_value(pic, :legende, locale),
262
- credits: localized_value(pic, :copyright, locale),
263
- expiration_date: pic[:dateLimiteDePublication]
264
- }
265
- end
266
- end
267
- end
268
- {pictures: pics_data}
269
- end
270
-
271
- def self.parse_attachments_data(attachments_array, *locales)
272
- atts_data = {}
273
- unless attachments_array.blank?
274
- l = locales.blank? ? [DEFAULT_LOCALE] : locales
275
- l.each do |locale|
276
- atts_data[locale] = []
277
- attachments_array.select { |att| att.is_a?(Hash) && !att[:traductionFichiers].blank? }.each do |att|
278
- atts_data[locale] << {
279
- id: att[:identifiant],
280
- name: localized_value(att, :nom, locale),
281
- url: att[:traductionFichiers][0][:url].gsub('http:', 'https:'),
282
- type: att[:type],
283
- description: localized_value(att, :legende, locale)
284
- }
285
- end
286
- end
287
- end
288
- {attachments: atts_data}
289
- end
290
-
291
- def self.contact(information_hash)
292
- contact_details = {}
293
- unless information_hash.blank?
294
- contact_entries = information_hash[:moyensCommunication] || []
295
- contact_entries.each do |c|
296
- case c[:type][:id]
297
- when PHONE
298
- contact_details[:telephone] ||= []
299
- contact_details[:telephone] << c[:coordonnees][:fr]
300
- when EMAIL
301
- contact_details[:email] ||= []
302
- contact_details[:email] << c[:coordonnees][:fr]
303
- when WEBSITE
304
- contact_details[:website] ||= []
305
- contact_details[:website] << c[:coordonnees][:fr]
306
- else
307
- end
308
- end
309
- end
310
- contact_details
311
- end
312
-
313
- def self.parse_location_data(location_hash, type_data_hash, territories)
314
- loc_data = {}
315
- unless location_hash.blank?
316
- address_hash = location_hash[:adresse]
317
- computed_address = []
318
- unless address_hash.blank?
319
- computed_address << address_hash[:adresse1] unless address_hash[:adresse1].blank?
320
- computed_address << address_hash[:adresse2] unless address_hash[:adresse2].blank?
321
- computed_address << address_hash[:adresse3] unless address_hash[:adresse3].blank?
322
- end
323
- loc_data.merge!({address: computed_address})
324
- loc_data.merge!({place: type_data_hash[:nomLieu]}) if type_data_hash
325
- geoloc_details = location_hash[:geolocalisation]
326
- if geoloc_details && geoloc_details[:valide] && geoloc_details[:geoJson]
327
- loc_data[:latitude] = geoloc_details[:geoJson][:coordinates][1]
328
- loc_data[:longitude] = geoloc_details[:geoJson][:coordinates][0]
329
- end
330
- loc_data[:access] = node_value(geoloc_details, :complement) if geoloc_details
331
- loc_data[:environments] = location_hash[:environnements].map {|e| e[:id]} if location_hash[:environnements]
332
- end
333
- loc_data[:territories] = territories.map {|t| t[:id]} unless territories.blank?
334
- loc_data
335
- end
336
-
337
- def self.town(location_hash)
338
- if location_hash
339
- address_hash = location_hash[:adresse]
340
- (!address_hash.blank? && address_hash[:commune]) ? Town.find_by_apidae_id(address_hash[:commune][:id]) : nil
341
- else
342
- nil
343
- end
344
- end
345
-
346
- # Note : use internal format for openings storage (ideally Apihours one, to merge data from both sources)
347
- def self.parse_openings(openings_hash, *locales)
348
- if openings_hash && openings_hash[:periodeEnClair]
349
- {
350
- openings_desc: node_value(openings_hash, :periodeEnClair, *locales),
351
- openings_desc_mode: openings_hash[:periodeEnClairGenerationMode] == 'AUTOMATIQUE' ? MODE_AUTO : MODE_MANUAL,
352
- openings: openings_hash[:periodesOuvertures],
353
- time_periods: lists_ids(openings_hash[:indicationsPeriode])
354
- }
355
- end
356
- end
357
-
358
- def self.parse_rates(rates_hash, *locales)
359
- if rates_hash
360
- desc = rates_hash[:gratuit] ? {DEFAULT_LOCALE => 'gratuit'} : node_value(rates_hash, :tarifsEnClair, *locales)
361
- values = rates_hash[:periodes].blank? ? [] : rates_hash[:periodes].map {|p| build_rate(p)}
362
- methods = rates_hash[:modesPaiement].blank? ? [] : rates_hash[:modesPaiement].map {|p| p[:id]}
363
- {
364
- rates_desc: desc, rates: values, payment_methods: methods,
365
- rates_desc_mode: rates_hash[:tarifsEnClairGenerationMode] == 'AUTOMATIQUE' ? MODE_AUTO : MODE_MANUAL,
366
- includes: node_value(rates_hash, :leTarifComprend, *locales),
367
- excludes: node_value(rates_hash, :leTarifNeComprendPas, *locales)
368
- }
369
- end
370
- end
371
-
372
- def self.parse_type_data(apidae_obj, type_hash, presta_hash, business_hash, *locales)
373
- data_hash = type_hash || {}
374
- prestations_hash = presta_hash || {}
375
- apidae_obj.apidae_subtype = lists_ids(data_hash[:typesManifestation]).first if apidae_obj.apidae_type == FEM
376
- apidae_obj.apidae_subtype = node_id(data_hash, :rubrique) if apidae_obj.apidae_type == EQU
377
- apidae_obj.apidae_subtype = lists_ids(data_hash[:typesHebergement]).first if apidae_obj.apidae_type == SPA
378
- {
379
- categories: lists_ids(data_hash[:categories], data_hash[:typesDetailles], data_hash[:activiteCategories]),
380
- themes: lists_ids(data_hash[:themes]),
381
- capacity: (data_hash[:capacite] || {})
382
- .merge(presta_hash ? {group_min: presta_hash[:tailleGroupeMin], group_max: presta_hash[:tailleGroupeMax],
383
- age_min: presta_hash[:ageMin], age_max: presta_hash[:ageMax]} : {}),
384
- classification: nodes_ids(data_hash[:classement], data_hash[:classementPrefectoral], data_hash[:classification]) +
385
- lists_ids(data_hash[:classementsGuides]) + lists_ids(data_hash[:classements]),
386
- labels: lists_ids(data_hash[:labels], data_hash[:labelsChartesQualite], prestations_hash[:labelsTourismeHandicap]) +
387
- (node_id(data_hash, :typeLabel) ? [node_id(data_hash, :typeLabel)] : []),
388
- chains: lists_ids(data_hash[:chaines]) + nodes_ids(data_hash[:chaineEtLabel]),
389
- area: apidae_obj.apidae_type == DOS ? data_hash.except(:classification) : node_value(data_hash, :lieuDePratique),
390
- track: apidae_obj.apidae_type == EQU ? data_hash[:itineraire] : nil,
391
- products: lists_ids(data_hash[:typesProduit], data_hash[:aopAocIgps], data_hash[:specialites]),
392
- audience: lists_ids(prestations_hash[:typesClientele]),
393
- animals: prestations_hash[:animauxAcceptes] == 'ACCEPTES',
394
- extra: apidae_obj.apidae_type == SPA ? node_value(data_hash, :formuleHebergement, *locales) : node_value(prestations_hash, :complementAccueil, *locales),
395
- duration: apidae_obj.apidae_type == SPA ? {days: data_hash[:nombreJours], nights: data_hash[:nombreNuits]} : data_hash[:dureeSeance],
396
- certifications: data_hash[:agrements].blank? ? [] : data_hash[:agrements].map {|a| {id: a[:type][:id], identifier: a[:numero]}},
397
- business: business_hash
398
- }
399
- end
400
-
401
- def self.parse_service_data(data_hash, type_data_hash)
402
- if data_hash
403
- {
404
- services: lists_ids(data_hash[:services]),
405
- equipments: lists_ids(data_hash[:equipements]),
406
- comfort: lists_ids(data_hash[:conforts]),
407
- activities: lists_ids(data_hash[:activites], type_data_hash ? type_data_hash[:activites] : [],
408
- type_data_hash ? type_data_hash[:activitesSportives] : [],
409
- type_data_hash ? type_data_hash[:activitesCulturelles] : []),
410
- challenged: lists_ids(data_hash[:tourismesAdaptes]),
411
- languages: lists_ids(data_hash[:languesParlees])
412
- }
413
- end
414
- end
415
-
416
- def self.parse_tags_data(pres_data_hash, crit_data_hash, linked_data_hash)
417
- tags = {}
418
- if pres_data_hash
419
- tags[:promo] = lists_ids(pres_data_hash[:typologiesPromoSitra])
420
- end
421
- unless crit_data_hash.blank?
422
- tags[:internal] = crit_data_hash.map {|c| c[:id]}
423
- end
424
- unless linked_data_hash.blank? || linked_data_hash[:liensObjetsTouristiquesTypes].blank?
425
- tags[:linked] = linked_data_hash[:liensObjetsTouristiquesTypes]
426
- .map {|l| {apidae_id: l[:objetTouristique][:id], apidae_type: l[:objetTouristique][:type], category: l[:type]}}
427
- end
428
- tags
429
- end
430
-
431
- def self.parse_booking(reservation_hash, *locales)
432
- if reservation_hash
433
- {
434
- booking_desc: node_value(reservation_hash, :complement, *locales),
435
- booking_entities: reservation_hash[:organismes]
436
- }
437
- end
438
- end
439
-
440
- def self.entity_fields(information_hash, type_data_hash)
441
- if information_hash && information_hash[:structureGestion]
442
- {entity_id: information_hash[:structureGestion][:id], service_provider_id: node_id(type_data_hash, :prestataireActivites)}
443
- end
444
- end
445
-
446
191
  def contact_text
447
192
  entries = []
448
- JSON.parse(contact).each_pair do |k, v|
193
+ JSON.parse(contact_data).each_pair do |k, v|
449
194
  entries << "#{k}: #{v}"
450
195
  end
451
196
  entries.join("\n")
@@ -454,48 +199,5 @@ module Apidae
454
199
  def main_picture
455
200
  pictures.blank? ? "/#{Rails.application.config.apidae_pictures_path}/default/logo.png" : pictures[0]["url"].gsub('http:', 'https:')
456
201
  end
457
-
458
- def self.build_rate(rate_period)
459
- {
460
- id: rate_period[:identifiant], start_date: rate_period[:dateDebut], end_date: rate_period[:dateFin],
461
- values: rate_period[:tarifs].blank? ? [] : rate_period[:tarifs].map {|t| {min: t[:minimum], max: t[:maximum], type: t[:type][:id], details: node_value(t, :precisionTarif)}}
462
- }
463
- end
464
-
465
- private
466
-
467
- def self.node_value(node, key, *locales)
468
- l = locales.blank? ? [DEFAULT_LOCALE] : locales
469
- locales_map = Hash[l.map {|loc| [localized_key(loc), loc]}]
470
- if node && node[key]
471
- node[key].slice(*locales_map.keys).transform_keys {|k| locales_map[k]}
472
- else
473
- {}
474
- end
475
- end
476
-
477
- def self.localized_value(node, key, loc)
478
- if node && node[key]
479
- node[key][localized_key(loc)]
480
- else
481
- ''
482
- end
483
- end
484
-
485
- def self.node_id(node, key)
486
- node[key][:id] if node && node[key]
487
- end
488
-
489
- def self.lists_ids(*lists)
490
- lists.blank? ? [] : lists.map {|l| l.blank? ? [] : l.map {|elt| elt[:id]}}.flatten.uniq
491
- end
492
-
493
- def self.nodes_ids(*nodes)
494
- nodes.blank? ? [] : nodes.select {|n| !n.blank?}.map {|n| n[:id]}
495
- end
496
-
497
- def self.localized_key(loc = DEFAULT_LOCALE)
498
- "libelle#{loc.camelize.gsub('-', '')}".to_sym
499
- end
500
202
  end
501
203
  end