locabulary 0.3.1 → 0.5.0

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
  SHA1:
3
- metadata.gz: 399c1a9f7cf3a7365116f94bd18cefa4c5ccd240
4
- data.tar.gz: 9399cbc0fcd7b6a8d8b1839b79225e3061bd5fb5
3
+ metadata.gz: 4c1e85110e906091033981d644e5a147c001eab2
4
+ data.tar.gz: 1cf448e30e0d19469afafee922ac3f3a5d01f025
5
5
  SHA512:
6
- metadata.gz: 74c9bb11679cea1e9c2831a995607426db1494028a5b147171e24233b11fe1378221769bb210c3f8f1e6331960502cdbf24b61f6167f3b3836da31baeffe312b
7
- data.tar.gz: e1a7b89c4e1583ecbb29e2b0137fa3422d9b33ec4e2ec3afd6ac2f228f48a11afecc5ffcb4daa32d334196e73ca213b44957c79f02aa9402eac2505840823b3c
6
+ metadata.gz: 105285fc4f39faa1f49d78a5245a67fbb975c31656f62f430e831d256a0f6adb1810936695a068c015ce16674e5ffa503d8f3745624a97265515e94453201772
7
+ data.tar.gz: d0337a83c1248bb28b87494350e59770ddf9834480b4284a39bbb57289d9af24c3389fb831407a258b7d3709b72ce7e9e21ee6d633f0a2a2309c91ec49b306d3
@@ -0,0 +1,4 @@
1
+ speedups:
2
+ each_with_index_vs_while: false
3
+ exclude_paths:
4
+ - 'vendor/**/*.rb'
data/.hound.yml CHANGED
@@ -21,6 +21,7 @@ AllCops:
21
21
  - 'tmp/**/*'
22
22
  - 'bin/**/*'
23
23
  - 'lib/milan/registry.rb'
24
+ - 'script/*'
24
25
  TargetRubyVersion: 2.2
25
26
  Rails:
26
27
  Enabled: false
File without changes
data/Gemfile CHANGED
@@ -2,6 +2,3 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in vocabulary.gemspec
4
4
  gemspec
5
-
6
- gem 'dry-validation', github: 'dry-rb/dry-validation'
7
- gem 'dry-types', github: 'dry-rb/dry-types'
data/README.md CHANGED
@@ -10,3 +10,7 @@
10
10
  An extraction of limited localized vocabulary for Sipity and CurateND.
11
11
  This controlled vocabulary has a limited shelf-life as we explore other more
12
12
  robust options.
13
+
14
+ ## Testing
15
+
16
+ The full test suite is run via `bundle exec rake`.
data/Rakefile CHANGED
@@ -21,6 +21,16 @@ namespace :commitment do
21
21
  task :configure_test_for_code_coverage do
22
22
  ENV['COVERAGE'] = 'true'
23
23
  end
24
+ desc "Check for code that can go faster"
25
+ task :fasterer do
26
+ require 'fasterer/file_traverser'
27
+ file_traverser = Fasterer::FileTraverser.new(nil)
28
+ file_traverser.traverse
29
+ if file_traverser.offenses_found?
30
+ $stderr.puts "You can make the code go faster, see above. You can add exceptions in .fasterer.yml"
31
+ abort
32
+ end
33
+ end
24
34
  task :code_coverage do
25
35
  require 'json'
26
36
  $stdout.puts "Checking code_coverage"
@@ -38,5 +48,5 @@ namespace :commitment do
38
48
  end
39
49
  end
40
50
 
41
- task(default: [:rubocop, 'commitment:configure_test_for_code_coverage', :spec, 'commitment:code_coverage'])
51
+ task(default: [:rubocop, 'commitment:fasterer', 'commitment:configure_test_for_code_coverage', :spec, 'commitment:code_coverage'])
42
52
  task(release: :default)
@@ -6,12 +6,14 @@
6
6
  "term_label": "University of Notre Dame",
7
7
  "classification": "University",
8
8
  "homepage": "http://www.nd.edu/",
9
- "activated_on": "2015-07-22"
9
+ "activated_on": "2015-07-22",
10
+ "default_presentation_sequence": 1
10
11
  },
11
12
  {
12
13
  "predicate_name": "administrative_units",
13
14
  "term_label": "University of Notre Dame::School of Architecture",
14
15
  "classification": "College",
16
+ "default_presentation_sequence": 1,
15
17
  "homepage": "http://architecture.nd.edu/",
16
18
  "activated_on": "2015-07-22"
17
19
  },
@@ -20,6 +22,7 @@
20
22
  "term_label": "University of Notre Dame::College of Arts and Letters",
21
23
  "grouping": "The Humanities",
22
24
  "classification": "College",
25
+ "default_presentation_sequence": 2,
23
26
  "homepage": "http://al.nd.edu/",
24
27
  "activated_on": "2015-07-22"
25
28
  },
@@ -196,6 +199,7 @@
196
199
  "predicate_name": "administrative_units",
197
200
  "term_label": "University of Notre Dame::Mendoza College of Business",
198
201
  "classification": "College",
202
+ "default_presentation_sequence": 3,
199
203
  "homepage": "http://mendoza.nd.edu/",
200
204
  "activated_on": "2015-07-22"
201
205
  },
@@ -238,6 +242,7 @@
238
242
  "predicate_name": "administrative_units",
239
243
  "term_label": "University of Notre Dame::College of Engineering",
240
244
  "classification": "College",
245
+ "default_presentation_sequence": 4,
241
246
  "homepage": "http://engineering.nd.edu/",
242
247
  "activated_on": "2015-07-22"
243
248
  },
@@ -287,6 +292,7 @@
287
292
  "predicate_name": "administrative_units",
288
293
  "term_label": "University of Notre Dame::College of Science",
289
294
  "classification": "College",
295
+ "default_presentation_sequence": 5,
290
296
  "homepage": "http://science.nd.edu/",
291
297
  "activated_on": "2015-07-22"
292
298
  },
@@ -343,6 +349,7 @@
343
349
  "predicate_name": "administrative_units",
344
350
  "term_label": "University of Notre Dame::First Year of Studies",
345
351
  "classification": "College",
352
+ "default_presentation_sequence": 6,
346
353
  "homepage": "http://firstyear.nd.edu/",
347
354
  "activated_on": "2015-07-22"
348
355
  },
@@ -350,6 +357,7 @@
350
357
  "predicate_name": "administrative_units",
351
358
  "term_label": "University of Notre Dame::Graduate School",
352
359
  "classification": "College",
360
+ "default_presentation_sequence": 7,
353
361
  "homepage": "http://graduateschool.nd.edu/",
354
362
  "activated_on": "2015-07-22"
355
363
  },
@@ -357,6 +365,7 @@
357
365
  "predicate_name": "administrative_units",
358
366
  "term_label": "University of Notre Dame::Law School",
359
367
  "classification": "College",
368
+ "default_presentation_sequence": 8,
360
369
  "homepage": "http://law.nd.edu/",
361
370
  "activated_on": "2015-07-22"
362
371
  },
@@ -364,6 +373,7 @@
364
373
  "predicate_name": "administrative_units",
365
374
  "term_label": "University of Notre Dame::Reserve Officers Training Corps",
366
375
  "classification": "College",
376
+ "default_presentation_sequence": 9,
367
377
  "activated_on": "2015-07-22"
368
378
  },
369
379
  {
@@ -398,12 +408,13 @@
398
408
  "predicate_name": "administrative_units",
399
409
  "term_label": "University of Notre Dame::Hesburgh Libraries",
400
410
  "classification": "College",
411
+ "default_presentation_sequence": 10,
401
412
  "homepage": "http://library.nd.edu/",
402
413
  "activated_on": "2015-07-22"
403
414
  },
404
415
  {
405
416
  "predicate_name": "administrative_units",
406
- "term_label": "University of Notre Dame::Hesburgh Libraries::General Collection",
417
+ "term_label": "University of Notre Dame::Hesburgh Libraries::General",
407
418
  "classification": "Department",
408
419
  "activated_on": "2015-07-22"
409
420
  },
@@ -425,6 +436,7 @@
425
436
  "predicate_name": "administrative_units",
426
437
  "term_label": "University of Notre Dame::Centers and Institutes",
427
438
  "classification": "CenterOrInstitute",
439
+ "default_presentation_sequence": 11,
428
440
  "activated_on": "2015-07-22"
429
441
  },
430
442
  {
@@ -876,6 +888,19 @@
876
888
  "affiliation": "University of Notre Dame::College of Engineering",
877
889
  "homepage": "http://wireless.nd.edu/",
878
890
  "activated_on": "2015-07-22"
891
+ },
892
+ {
893
+ "predicate_name": "administrative_units",
894
+ "term_label": "Catholic Organizations",
895
+ "classification": "OrganizationalGroup",
896
+ "activated_on": "2015-07-22"
897
+ },
898
+ {
899
+ "predicate_name": "administrative_units",
900
+ "term_label": "Catholic Organizations::Catholic Research Resources Alliance",
901
+ "classification": "Organization",
902
+ "homepage": "http://www.catholicresearch.net/",
903
+ "activated_on": "2015-07-22"
879
904
  }
880
905
  ]
881
906
  }
@@ -2,27 +2,27 @@
2
2
  "predicate_name": "college",
3
3
  "values": [{
4
4
  "term_label": "School of Architecture",
5
- "default_presentation_sequence": 60,
5
+ "default_presentation_sequence": 10,
6
+ "activated_on": "2015-07-22"
7
+ },{
8
+ "term_label": "College of Arts and Letters",
9
+ "default_presentation_sequence": 20,
6
10
  "activated_on": "2015-07-22"
7
11
  },{
8
12
  "term_label": "Mendoza College of Business",
9
- "default_presentation_sequence": 50,
13
+ "default_presentation_sequence": 30,
10
14
  "activated_on": "2015-07-22"
11
15
  },{
12
16
  "term_label": "College of Engineering",
13
- "default_presentation_sequence": 20,
17
+ "default_presentation_sequence": 40,
14
18
  "activated_on": "2015-07-22"
15
19
  },{
16
20
  "term_label": "College of Science",
17
- "default_presentation_sequence": 30,
18
- "activated_on": "2015-07-22"
19
- },{
20
- "term_label": "College of Arts and Letters",
21
- "default_presentation_sequence": 10,
21
+ "default_presentation_sequence": 50,
22
22
  "activated_on": "2015-07-22"
23
23
  },{
24
- "term_label": "First Year Studies",
25
- "default_presentation_sequence": 40,
24
+ "term_label": "First Year of Studies",
25
+ "default_presentation_sequence": 60,
26
26
  "activated_on": "2015-12-14"
27
27
  }]
28
28
  }
@@ -0,0 +1,24 @@
1
+ {
2
+ "predicate_name": "spec",
3
+ "values": [
4
+ {
5
+ "predicate_name": "spec",
6
+ "term_label": "Active Item",
7
+ "default_presentation_sequence": 3,
8
+ "activated_on": "2015-07-22"
9
+ },
10
+ {
11
+ "predicate_name": "spec",
12
+ "term_label": "Deactive Item",
13
+ "default_presentation_sequence": 1,
14
+ "activated_on": "2015-07-22",
15
+ "deactivated_on": "2016-07-01"
16
+ },
17
+ {
18
+ "predicate_name": "spec",
19
+ "term_label": "Alternate Item",
20
+ "default_presentation_sequence": 2,
21
+ "activated_on": "2015-07-22"
22
+ }
23
+ ]
24
+ }
@@ -13,7 +13,7 @@
13
13
  "default_presentation_sequence": 3,
14
14
  "activated_on": "2015-01-01"
15
15
  },{
16
- "term_label": "Junior",
16
+ "term_label": "Senior",
17
17
  "default_presentation_sequence": 4,
18
18
  "activated_on": "2015-01-01"
19
19
  },{
@@ -1,125 +1,117 @@
1
1
  require 'date'
2
2
  require 'json'
3
3
  require 'locabulary/exceptions'
4
- require 'locabulary/items'
4
+ require 'locabulary/item'
5
+ require 'locabulary/commands/build_ordered_hierarchical_tree_command'
6
+ require 'locabulary/commands/active_items_for_command'
7
+ require 'locabulary/commands/active_hierarchical_roots_command'
5
8
 
6
9
  # @since 0.1.0
7
10
  module Locabulary
8
- DATA_DIRECTORY = File.expand_path("../../data/", __FILE__).freeze
9
-
10
- module_function
11
+ # @api private
12
+ # @since 0.5.0
13
+ #
14
+ # Responsible for building a hierarchical tree from faceted items, and ordering the nodes as per the presentation sequence for the
15
+ # associated predicate_name.
16
+ #
17
+ # @param [Hash] options
18
+ # @option options [String] :predicate_name
19
+ # @option options [Array<#hits, #value>] :faceted_items
20
+ # @option options [String] :faceted_item_hierarchy_delimiter
21
+ # @return Array[<FacetWrapperForItem>]
22
+ #
23
+ # @see Locabulary::Commands::BuildOrderedHierarchicalTree
24
+ def self.build_ordered_hierarchical_tree(options = {})
25
+ Commands::BuildOrderedHierarchicalTreeCommand.call(options)
26
+ end
11
27
 
12
28
  # @api public
13
29
  # @since 0.1.0
14
30
  #
15
- # @note A concession about the as_of; This is not a live query. The data has a
16
- # low churn rate. And while the date is important, I'm not as concerned
17
- # about the local controlled vocabulary exposing a date that has expired.
18
- # When we next deploy the server changes, the deactivated will go away.
19
- def active_items_for(options = {})
20
- predicate_name = options.fetch(:predicate_name)
21
- as_of = options.fetch(:as_of) { Date.today }
22
- builder = Items.builder_for(predicate_name: predicate_name)
23
- active_cache[predicate_name] ||= begin
24
- collector = []
25
- with_active_extraction_for(predicate_name, as_of) do |data|
26
- collector << builder.call(data.merge('predicate_name' => predicate_name))
27
- end
28
- collector.sort
29
- end
31
+ # Responsible for extracting a non-hierarchical sorted array of Locabulary::Items::Base objects for the given predicate_name.
32
+ #
33
+ # @param [Hash] options
34
+ # @option options [String] :predicate_name
35
+ # @option options [Date] :as_of (Date.today)
36
+ # @return Array[<Locabulary::Items::Base>]
37
+ #
38
+ # @see Locabulary::Commands::ActiveItemsForCommand
39
+ def self.active_items_for(options = {})
40
+ Commands::ActiveItemsForCommand.call(options)
30
41
  end
31
42
 
32
43
  # @api public
33
- # @since 0.2.0
34
- def active_hierarchical_root(options = {})
35
- predicate_name = options.fetch(:predicate_name)
36
- as_of = options.fetch(:as_of) { Date.today }
37
- builder = Items.builder_for(predicate_name: predicate_name)
38
- active_hierarchical_root_cache[predicate_name] ||= begin
39
- items = []
40
- hierarchy_graph_keys = {}
41
- top_level_slugs = Set.new
42
- with_active_extraction_for(predicate_name, as_of) do |data|
43
- item = builder.call(data.merge('predicate_name' => predicate_name))
44
- items << item
45
- top_level_slugs << item.root_slug
46
- hierarchy_graph_keys[item.term_label] = item
47
- end
48
- associate_parents_and_childrens_for(hierarchy_graph_keys, items, predicate_name)
49
- raise Exceptions::TooManyHierarchicalRootsError.new(predicate_name, top_level_slugs.to_a) if top_level_slugs.size > 1
50
- hierarchy_graph_keys.fetch(top_level_slugs.first)
51
- end
52
- end
53
-
54
- def associate_parents_and_childrens_for(hierarchy_graph_keys, items, predicate_name)
55
- items.each do |item|
56
- begin
57
- hierarchy_graph_keys.fetch(item.parent_term_label).add_child(item) unless item.parent_slugs.empty?
58
- rescue KeyError => error
59
- raise Exceptions::MissingHierarchicalParentError.new(predicate_name, error)
60
- end
61
- end
44
+ # @since 0.4.0
45
+ #
46
+ # Responsible for transforming the flat data for the given :predicate_name
47
+ # into a hierarchy.
48
+ #
49
+ # @param [Hash] options
50
+ # @option options [String] :predicate_name
51
+ # @option options [Date] :as_of (Date.today)
52
+ # @return [Array<Locabulary::Items::Base>] - the root nodes
53
+ def self.active_hierarchical_roots(options = {})
54
+ Commands::ActiveHierarchicalRootsCommand.call(options)
62
55
  end
63
- private :associate_parents_and_childrens_for
64
56
 
65
- def with_active_extraction_for(predicate_name, as_of)
66
- filename = filename_for_predicate_name(predicate_name: predicate_name)
67
- json = JSON.parse(File.read(filename))
68
- json.fetch('values').each do |data|
69
- yield(data) if data_is_active?(data, as_of)
57
+ # @api public
58
+ # @since 0.5.0
59
+ # @param options [Hash]
60
+ # @option options [String] :predicate_name
61
+ # @option options [String] :term_label
62
+ # @option options [Date] :as_of (Date.today)
63
+ # @raise [Locabulary::Exceptions::ItemNotFoundError] if unable to find label for predicate_name
64
+ # @return [Locabulary::Items::Base]
65
+ def self.item_for(options = {})
66
+ predicate_name = options.fetch(:predicate_name)
67
+ term_label = options.fetch(:term_label)
68
+ as_of = options.fetch(:as_of) { Date.today }
69
+ item = nil
70
+ Utility.with_extraction_for(predicate_name) do |data|
71
+ next unless data.fetch('term_label') == term_label
72
+ item = Item.build(data.merge('predicate_name' => predicate_name))
73
+ break if Utility.data_is_active?(data, as_of)
70
74
  end
75
+ return item unless item.nil?
76
+ raise Locabulary::Exceptions::ItemNotFoundError.new(predicate_name, term_label)
71
77
  end
72
- private :with_active_extraction_for
73
-
74
- def data_is_active?(data, as_of)
75
- activated_on = Date.parse(data.fetch('activated_on'))
76
- return false unless activated_on < as_of
77
- deactivated_on_value = data.fetch('deactivated_on', nil)
78
- return true if deactivated_on_value.nil?
79
- deactivated_on = Date.parse(deactivated_on_value)
80
- return false unless deactivated_on >= as_of
81
- true
82
- end
83
- private :data_is_active?
84
78
 
85
79
  # @api public
86
80
  # @since 0.1.0
87
- def active_label_for_uri(options = {})
88
- predicate_name = options.fetch(:predicate_name)
81
+ #
82
+ # @param [Hash] options
83
+ # @option options [String] :predicate_name
84
+ # @option options [String] :term_uri
85
+ # @option options [String] :as_of (Date.today)
86
+ #
87
+ # @return [String] a label or URI
88
+ #
89
+ # @see Locabulary.active_items_for
90
+ def self.active_label_for_uri(options = {})
89
91
  term_uri = options.fetch(:term_uri)
90
- object = active_items_for(predicate_name: predicate_name).detect { |obj| obj.term_uri == term_uri }
92
+ object = active_items_for(options).detect { |obj| obj.term_uri == term_uri }
91
93
  return object.term_label if object
92
94
  term_uri
93
95
  end
94
96
 
95
97
  # @api public
96
98
  # @since 0.1.0
97
- def active_labels_for(options = {})
98
- predicate_name = options.fetch(:predicate_name)
99
- active_items_for(predicate_name: predicate_name).map(&:term_label)
100
- end
101
-
102
- # @api private
103
- def filename_for_predicate_name(options = {})
104
- predicate_name = options.fetch(:predicate_name)
105
- filename = File.join(DATA_DIRECTORY, "#{File.basename(predicate_name)}.json")
106
- return filename if File.exist?(filename)
107
- raise Locabulary::Exceptions::RuntimeError, "Unable to find predicate_name: #{predicate_name}"
108
- end
109
-
110
- # @api private
111
- def active_cache
112
- @active_cache ||= {}
113
- end
114
-
115
- # @api private
116
- def active_hierarchical_root_cache
117
- @active_hierarchical_root_cache ||= {}
99
+ #
100
+ # Return an Array of term labels for the given :predicate_name
101
+ #
102
+ # @param [Hash] options
103
+ # @option options [String] :predicate_name
104
+ # @option options [String] :as_of (Date.today)
105
+ # @return [Array<String>] an array of Locabuarly::Items::Base#term_label
106
+ #
107
+ # @see Locabulary.active_items_for
108
+ def self.active_labels_for(options = {})
109
+ active_items_for(options).map(&:term_label)
118
110
  end
119
111
 
120
112
  # @api private
121
- def reset_active_cache!
122
- @active_cache = nil
123
- @active_hierarchical_root_cache = nil
113
+ def self.reset_active_cache!
114
+ Commands::ActiveItemsForCommand.reset_cache!
115
+ Commands::ActiveHierarchicalRootsCommand.reset_cache!
124
116
  end
125
117
  end