umlaut 4.0.3 → 4.1.0.pre.2

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.
Files changed (39) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +6 -0
  3. data/app/assets/javascripts/umlaut/update_html.js +81 -23
  4. data/app/assets/stylesheets/umlaut/_misc.scss +1 -2
  5. data/app/assets/stylesheets/umlaut/_resolve.scss +44 -10
  6. data/app/controllers/export_email_controller.rb +2 -2
  7. data/app/controllers/feedback_controller.rb +1 -1
  8. data/app/controllers/umlaut/controller_behavior.rb +14 -0
  9. data/app/controllers/umlaut_configurable.rb +52 -21
  10. data/app/helpers/open_search_helper.rb +1 -1
  11. data/app/helpers/resolve_helper.rb +36 -35
  12. data/app/helpers/umlaut/section_highlights.rb +85 -0
  13. data/app/mixin_logic/metadata_helper.rb +11 -5
  14. data/app/models/collection.rb +129 -96
  15. data/app/models/dispatched_service.rb +4 -0
  16. data/app/models/referent.rb +7 -1
  17. data/app/models/request.rb +21 -0
  18. data/app/models/service_store.rb +16 -3
  19. data/app/presentation/section_renderer.rb +16 -17
  20. data/app/service_adaptors/blacklight.rb +11 -4
  21. data/app/service_adaptors/internet_archive.rb +58 -25
  22. data/app/service_adaptors/isi.rb +14 -4
  23. data/app/service_adaptors/jcr.rb +13 -4
  24. data/app/views/resolve/_fulltext.html.erb +1 -1
  25. data/app/views/resolve/_section_display.html.erb +1 -1
  26. data/app/views/resolve/_service_errors.html.erb +3 -3
  27. data/app/views/search/books.html.erb +1 -1
  28. data/app/views/search/journal_search.html.erb +2 -1
  29. data/app/views/search/journals.html.erb +2 -1
  30. data/db/orig_fixed_data/service_type_values.yml +15 -37
  31. data/lib/aws_product_sign.rb +1 -1
  32. data/lib/generators/templates/umlaut_services.yml +5 -2
  33. data/lib/generators/umlaut/install_generator.rb +1 -0
  34. data/{app/models → lib}/service_type_value.rb +36 -22
  35. data/lib/umlaut/routes.rb +34 -5
  36. data/lib/umlaut/test_help.rb +159 -0
  37. data/lib/umlaut/version.rb +2 -2
  38. data/lib/umlaut.rb +44 -9
  39. metadata +10 -8
@@ -108,31 +108,30 @@ class InternetArchive < Service
108
108
  timeout(@http_timeout.to_i) {
109
109
  response = open(link).read
110
110
  }
111
+
111
112
  if response.blank?
112
113
  raise Exception.new("InternetArchive returned empty response for #{link}")
113
114
  end
114
115
 
115
-
116
116
  doc = MultiJson.load(response)
117
117
  results = doc['response']['docs']
118
118
 
119
119
  @mediatypes.each do |type|
120
- type_results = get_results_by_type(results, type)
121
-
122
-
120
+ hits = matching_hits(request, search_terms, results, type)
123
121
 
124
122
 
125
123
  # if we have more results than we want to show in the main view
126
124
  # we can ceate a link (highlighted_link) to the search in the sidebar
127
- num_found = type_results.length #doc['response']['numFound']
128
- if (@show_web_link and not type_results.empty? and @num_results_for_types[type] < num_found )
125
+
126
+ num_found = hits.length #doc['response']['numFound']
127
+ if (@show_web_link and not hits.empty? and @num_results_for_types[type] < num_found )
129
128
  do_web_link(request, search_terms, type, num_found)
130
129
  end
131
130
 
132
131
  # Check for search inside only for first result of type 'text'
133
132
  if (@include_search_inside &&
134
133
  type == 'texts' &&
135
- (first_hit = type_results[0]) &&
134
+ (first_hit = hits[0]) &&
136
135
  (identifier = first_hit["identifier"])
137
136
  )
138
137
  direct_url = URI.parse("http://www.archive.org/stream/" + identifier)
@@ -152,21 +151,21 @@ class InternetArchive < Service
152
151
  )
153
152
  end
154
153
  end
155
-
154
+
155
+
156
+
156
157
  # add a service response for each result for this mediatype
157
- type_results.each_with_index do |result, index|
158
- break if index == @num_results_for_types[type]
158
+ hits.each_with_index do |result, index|
159
+ break if index >= @num_results_for_types[type]
160
+
159
161
  display_name = @display_name
160
162
 
161
- if ( result["collection"] && COLLECTION_LABELS[result["collection"][0]])
163
+ if result["contributor"] && result["contributor"].first
164
+ display_name += ": " + result["contributor"].first
165
+ elsif ( result["collection"] && COLLECTION_LABELS[result["collection"][0]])
162
166
  display_name += ": " + COLLECTION_LABELS[result["collection"][0]]
163
- elsif ( result["collection"])
164
- display_name += ": " + result["collection"][0].titlecase
165
167
  end
166
168
 
167
- #note = result['title']
168
- #note << " by " << result['creator'].join(', ') if result['creator']
169
-
170
169
  service_type = SERVICE_TYPE_MAP[type]
171
170
  request.add_service_response(
172
171
  :service=>self,
@@ -175,7 +174,7 @@ class InternetArchive < Service
175
174
  :url=>create_result_url(result),
176
175
  :match_reliability => ServiceResponse::MatchUnsure,
177
176
  :edition_str => edition_str(result),
178
- :service_type_value => service_type )
177
+ :service_type_value => service_type )
179
178
  end
180
179
  end
181
180
  end
@@ -262,20 +261,54 @@ class InternetArchive < Service
262
261
 
263
262
  return output
264
263
  end
265
-
266
264
 
267
- def get_results_by_type(results, type)
268
- results.map{|doc| doc if doc["mediatype"] == type}.compact
265
+ def matching_hits(request, search_terms, results, type)
266
+ full_title = raw_search_title(request.referent)
267
+
268
+ hits = results.find_all do |r|
269
+ r["mediatype"] == type &&
270
+ titles_sufficiently_matched(search_terms[:title], full_title, r["title"])
271
+ end
272
+
273
+ return hits
274
+ end
275
+
276
+ # Some obtuse code to heuristically decide if our query title and a result
277
+ # title fuzzily match sufficiently to be considered a match.
278
+ def titles_sufficiently_matched(query_title, full_title, result)
279
+ normalized_query = normalize_title(query_title)
280
+ normalized_full_title = normalize_title(full_title)
281
+ # If the title has more than 3 words, and our IA query returned
282
+ # a result for it -- that's probably good enough.
283
+ return true if normalized_query.split(" ").length > 3
284
+
285
+
286
+ # Otherwise, make multiple versions of the candidate
287
+ # title -- the whole thing, the title until the first colon,
288
+ # and the title until the first comma or semi-colon or other punct. Normalize
289
+ # them all. See if any of them match EITHER our search title or
290
+ # our full title.
291
+ candidates = [
292
+ result,
293
+ result.split(":").first,
294
+ result.split(/[\;\,\(\)]/).first
295
+ ].compact.uniq.collect {|a| normalize_title(a)}
296
+
297
+ return (candidates & [normalized_query, normalized_full_title]).present?
269
298
  end
270
299
 
271
300
  def edition_str(result)
272
- parts = []
301
+ edition_str = ""
273
302
 
274
- parts.push( result['title']) unless result['title'].blank?
275
- parts.push( result['publisher'] ) unless result['publisher'].blank?
276
- parts.push( result['year']) unless result['year'].blank?
303
+ edition_str << result['title'] unless result['title'].blank?
277
304
 
278
- edition_str = parts.join(', ')
305
+ edition_str << " / #{result['creator'].first}" unless result['creator'].blank?
306
+ edition_str << ". #{result["publisher"].first}" unless result['publisher'].blank?
307
+ unless result['date'].blank?
308
+ year = result['date'].slice(0,4)
309
+ edition_str << ": #{year}"
310
+ end
311
+
279
312
  edition_str = nil if edition_str.blank?
280
313
 
281
314
  return edition_str
@@ -11,8 +11,9 @@
11
11
  # (LAMR) service api, which is used here. To register, see:
12
12
  # http://wokinfo.com/products_tools/products/related/amr/
13
13
  #
14
- # You register by IP address, so no API key is needed once your registration
15
- # goes through.
14
+ # You can register by IP address, so no auth key is needed once your registration
15
+ # goes through -- or fill out 'username' and 'password' config elements in service
16
+ # setup, and they will be used.
16
17
  #
17
18
  # If you later need to change the IP addresses entitled to use this API, use
18
19
  # http://scientific.thomson.com/scientific/techsupport/cpe/form.html.
@@ -126,8 +127,17 @@ class Isi < Service
126
127
  builder.request(:xmlns => "http://www.isinet.com/xrpc41", :src => "app.id=Umlaut") do
127
128
  builder.fn(:name => "LinksAMR.retrieve") do
128
129
  builder.list do
129
- # first map is authentication info. empty 'map' element since we are IP authenticated.
130
- builder.map
130
+ # first map is authentication info. empty 'map' element if we are IP authenticated.
131
+ if @username && @password
132
+ builder.map do
133
+ builder.val(@username, :name => "username")
134
+ builder.val(@password, :name => "password")
135
+ end
136
+ else
137
+ builder.map
138
+ end
139
+
140
+
131
141
  # specify what we're requesting
132
142
  builder.map do
133
143
  builder.list(:name=>"WOS") do
@@ -12,8 +12,9 @@
12
12
  # register, see:
13
13
  # http://wokinfo.com/products_tools/products/related/amr/
14
14
  #
15
- # You register by IP address, so no API key is needed once your registration
16
- # goes through.
15
+ # You register by IP address, so no auth info is needed once your registration
16
+ # goes through -- or you can receive a username and password, in which case
17
+ # you should configure keys 'username' and 'password'
17
18
  #
18
19
  # If you later need to change the IP addresses entitled to use this API, use
19
20
  # http://scientific.thomson.com/scientific/techsupport/cpe/form.html.
@@ -76,8 +77,16 @@ class Jcr < Service
76
77
  builder.request(:xmlns => "http://www.isinet.com/xrpc41", :src => "app.id=Umlaut") do
77
78
  builder.fn(:name => "LinksAMR.retrieve") do
78
79
  builder.list do
79
- # first map is authentication info. empty 'map' element since we are IP authenticated.
80
- builder.map
80
+ # first map is authentication info. empty 'map' element if we are IP authenticated.
81
+ if @username && @password
82
+ builder.map do
83
+ builder.val(@username, :name => "username")
84
+ builder.val(@password, :name => "password")
85
+ end
86
+ else
87
+ builder.map
88
+ end
89
+
81
90
  # specify what we're requesting
82
91
  builder.map do
83
92
  builder.list(:name=>"JCR") do
@@ -6,7 +6,7 @@ end
6
6
  # order em with full fulltxt before title_level_fulltxt
7
7
  all_responses = fulltxt + title_level_fulltxt
8
8
  %>
9
- <div class="<%= section_css_classes(@user_request, "fulltext", all_responses).join(" ") %>">
9
+ <div class="<%= section_css_classes(@user_request, "fulltext").join(" ") %>">
10
10
  <%= render 'section_heading', :presenter => renderer, :force_render => true %>
11
11
  <div class="umlaut_section_content">
12
12
  <%= list_with_limit('umlaut_fulltext', all_responses,
@@ -4,7 +4,7 @@
4
4
  -%>
5
5
  <% if presenter.visible? %>
6
6
  <% unless presenter.show_partial_only? %>
7
- <div class="<%= section_css_classes(@user_request, presenter.div_id, []).join(" ") %>">
7
+ <div class="<%= section_css_classes(@user_request, presenter.div_id).join(" ") %>">
8
8
  <% end %>
9
9
  <%= render 'section_heading', :presenter => presenter %>
10
10
  <% unless presenter.show_partial_only? %>
@@ -1,14 +1,14 @@
1
1
  <%
2
2
  failed_dispatches = failed_service_dispatches()
3
3
  unless ( failed_dispatches.nil? || failed_dispatches.empty? ) %>
4
- <div id="service_errors_content">
4
+ <div id="service_errors_content" class="alert alert-danger">
5
5
  <h5 class="warning"><i class="umlaut_icons-famfamfam-error"></i> <%= t 'umlaut.error.service_errors_title' %></h5>
6
6
  <ul class="list-unstyled">
7
7
  <% failed_dispatches.each do | dispatch | %>
8
8
  <li class="text-small">
9
9
  <%= t 'umlaut.error.services_missing' %><strong> <%= dispatch.service.service_types_generated.collect { |type|
10
- type.display_name_pluralize}.join(", ")%></strong>
11
- <%= t 'umlaut.resolve.from_service' %> <a class="collapse-toggle" data-target="<%= "#failed_dispatch_#{dispatch.id}"%>" data-toggle="collapse"><strong><%= dispatch.service.display_name %></strong></a>
10
+ type.display_name_pluralize}.uniq.join(", ")%></strong>
11
+ <%= t 'umlaut.resolve.from_service' %> <a class="collapse-toggle alert-link" data-target="<%= "#failed_dispatch_#{dispatch.id}"%>" data-toggle="collapse"><strong><%= dispatch.service.display_name %></strong></a>
12
12
  <% exception_info = dispatch.exception_info %>
13
13
  <div id="<%= "failed_dispatch_#{dispatch.id}"%>" class="collapse">
14
14
  <ul class="nav nav-list">
@@ -3,7 +3,7 @@
3
3
  <h1>Books</h1>
4
4
  <%= form_tag({:controller=>'resolve', :action=>@submit_action}, {:method=>'get', :class=>"form-horizontal"}) %>
5
5
  <fieldset class="citationLinker">
6
- <%= hidden_field_tag "rfr_id", "info:sid/umlaut.code4lib.org:citation" %>
6
+ <%= hidden_field_tag "rfr_id", umlaut_config.lookup!("rfr_ids.citation") %>
7
7
  <%= hidden_field_tag "url_ver", "Z39.88-2004" %>
8
8
  <%= hidden_field_tag "url_ctx_fmt", "info:ofi/fmt:kev:mtx:ctx" %>
9
9
  <%= hidden_field_tag "ctx_ver", "Z39.88-2004" %>
@@ -2,7 +2,8 @@
2
2
  <%= form_tag({:controller=>'search', :action=>'journal_search'}, {:method=>'get', :name=>'OpenURL', :id=>'OpenURL', :class => "form-inline form-very-inline"}) %>
3
3
  <div class="umlaut-search-form">
4
4
  <fieldset>
5
- <%= hidden_field_tag "rfr_id", "info:sid/sfxit.com:citation" %>
5
+
6
+ <%= hidden_field_tag "rfr_id", umlaut_config.lookup!("rfr_ids.citation") %>
6
7
  <%= hidden_field_tag "rft.title", "", {:class => "rft_title"} %>
7
8
  <%= hidden_field_tag "rft.object_id", "", {:class => "rft_object_id"} %>
8
9
  <%= hidden_field_tag "rft.issn", "" %>
@@ -8,7 +8,8 @@
8
8
  <div class="umlaut-search-form">
9
9
  <fieldset>
10
10
  <legend><%=t 'umlaut.search.journals_instructions' %></legend>
11
- <%= hidden_field_tag "rfr_id", "info:sid/sfxit.com:citation" %>
11
+
12
+ <%= hidden_field_tag "rfr_id", umlaut_config.lookup!("rfr_ids.citation") %>
12
13
  <%= hidden_field_tag "rft.date", "" %>
13
14
  <%= hidden_field_tag "rft.title", "", {:class => "rft_title"} %>
14
15
  <%= hidden_field_tag "rft.object_id", "", {:class => "rft_object_id"} %>
@@ -3,129 +3,107 @@
3
3
  #
4
4
  # Which makes this file at present just a list of names and ids; if we had
5
5
  # to do it over, we'd do this differently.
6
+ #
7
+ # You can add your own additional service types in a local app config/service_type_values.yml,
8
+ # or by calling ServiceTypeValue.merge_yml_file!(path_to_yml_file)
6
9
  fulltext:
7
- id: 1
8
- display_name: electronic_version
9
- display_name_plural: electronic_versions
10
+ display_name: Electronic Version
11
+ display_name_plural: Electronic Versions
10
12
 
11
13
  holding:
12
- id: 2
13
14
  display_name: Copy in Library
14
- display_name_plural: copies_in_library
15
+ display_name_plural: Copies in Library
15
16
 
16
17
  document_delivery:
17
- id: 3
18
18
  display_name: Request Service
19
- display_name_plural: request_services
19
+ display_name_plural: Request Services
20
20
 
21
21
  help:
22
- id: 4
23
22
  display_name: Help Link
24
- display_name_plural: help_links
23
+ display_name_plural: Help Links
25
24
 
26
25
  # Not currently used
27
26
  web_link:
28
- id: 5
29
27
  display_name: Web Result
30
- display_name_plural: web_results
28
+ display_name_plural: Web Results
31
29
 
32
30
  # Not currently used.
33
31
  relevant_link:
34
- id: 6
35
32
  display_name: Closest Web Result
36
33
 
37
34
  abstract:
38
- id: 11
39
35
  display_name: Abstract
40
- display_name_plural: abstracts
36
+ display_name_plural: Abstracts
41
37
 
42
38
  table_of_contents:
43
- id: 12
44
39
  display_name: Table of Contents
45
- display_name_plural: tables_of_content
40
+ display_name_plural: Tables of Contents
46
41
 
47
42
  cover_image:
48
- id: 13
49
43
  display_name: Cover Image
50
- display_name_plural: cover_images
44
+ display_name_plural: Cover Images
51
45
 
52
46
  # "See also" links to known destinations, like Amazon or OCLC
53
47
  highlighted_link:
54
- id: 14
55
48
  display_name: See Also Link
56
- display_name_plural: see_also_links
49
+ display_name_plural: See Also Links
57
50
 
58
51
  # Link to search holdings, generally with a count given, ie "5 possible matches".
59
52
  holding_search:
60
- id: 15
61
53
  display_name: Copy in Library
62
- display_name_plural: copies_in_library
54
+ display_name_plural: Copies in Library
63
55
 
64
56
  # This is meant for 'fulltext' from such sources as the OPAC/ILS, where
65
57
  # it will always be a title-level link, and dates of coverage usually
66
58
  # aren't checked. DEPRECATED. No longer used, use a fulltext wtih :coverage_checked
67
59
  # and/or :can_link_to_article set to false.
68
60
  fulltext_title_level:
69
- id: 16
70
61
  display_name: Electronic Text Version
71
62
 
72
63
  audio:
73
- id: 17
74
64
  display_name: Digital Audio
75
65
 
76
66
  # A search inside tool, presented with a search box for user.
77
67
  search_inside:
78
- id: 18
79
68
  display_name: Search Inside Tool
80
69
 
81
70
  # A tool that will enhance the Referent metadata. Not always advertised
82
71
  # properly yet.
83
72
  referent_enhance:
84
- id: 19
85
73
  display_name: More Information
86
74
 
87
75
  # Link to partial text, as in Amazon or Google Books that don't have
88
76
  # full text, only excerpts.
89
77
  excerpts:
90
- id: 20
91
78
  display_name: Limited Excerpts
92
79
 
93
80
  cited_by:
94
- id: 21
95
81
  display_name: Article that cites this
96
82
  display_name_plural: Articles that cite this
97
83
 
98
84
  # Used by ISI and Scopus at present. Maybe more later.
99
85
  # "More like this" links.
100
86
  similar:
101
- id: 22
102
87
  display_name: "Similar Articles"
103
88
 
104
89
 
105
90
  # Not sure what this is used for. Think it's a typo for abstract.
106
91
  description:
107
- id: 100
108
92
  display_name: Description
109
93
 
110
94
  # Not sure if this is used for anything yet, but some services generate
111
95
  subject:
112
- id: 101
113
96
  display_name: Subject
114
97
 
115
98
  # Not used yet by views
116
99
  similar_item:
117
- id: 102
118
100
  display_name: Similar Item
119
101
 
120
102
  # Used to save/send the citation/holdings
121
103
  export_citation:
122
- id: 103
123
104
  display_name: Export tool
124
- display_name_plural: export_tools
105
+ display_name_plural: Export Tools
125
106
 
126
107
  primo_source:
127
- id: 104
128
108
  display_name: Primo Source
129
109
 
130
- # If you want to add your own custom ones, make them start with ids at 100000,
131
- # to leave plenty of space for future standard umlaut ones.
@@ -85,7 +85,7 @@ class AwsProductSign
85
85
 
86
86
  # chomp is important! the base64 encoded version will have a newline at the end
87
87
  # which amazon does not want.
88
- digest = OpenSSL::Digest::Digest.new('sha256')
88
+ digest = OpenSSL::Digest.new('sha256')
89
89
  signature = Base64.encode64(OpenSSL::HMAC.digest(digest, secret_key, string_to_sign)).chomp
90
90
 
91
91
  params["Signature"] = signature
@@ -1,4 +1,3 @@
1
-
2
1
  # Configure what service plugins are used by Umlaut. This skeleton file
3
2
  # has been generated into your app to help you get started.
4
3
  #
@@ -8,10 +7,14 @@
8
7
  # Most services take other options for custom configuration too, not
9
8
  # all options are neccesarily listed as examples here, see source
10
9
  # or source-generated docs for more info.
11
-
10
+ #
12
11
  # The services in the 'default' group are loaded every time.
13
12
  # You can optionally create other groups of services, that can be loaded
14
13
  # by URL query params, or based on other request params. More info?
14
+ #
15
+ # This file is run through ERB, so you can use <%= %> tags for dynamic
16
+ # ruby content if you like.
17
+ #
15
18
 
16
19
  default:
17
20
  services:
@@ -1,3 +1,4 @@
1
+ require 'umlaut'
1
2
  require 'rails/generators'
2
3
 
3
4
  module Umlaut
@@ -2,7 +2,11 @@ require 'yaml'
2
2
 
3
3
 
4
4
  # This model is the actual list of valid service types. Not ActiveRecord,
5
- # just load from config files into memory (loaded on file load).
5
+ # just load from config/service_type_values.yml into memory (loaded on file load, initialization)
6
+ #
7
+ # This is stored in lib/ intentionally, to avoid Rails dev-mode auto-reloading,
8
+ # because we store state in this class, and reloading was losing state we
9
+ # intentionally set, eg for plugins adding new service types.
6
10
  #
7
11
  # ServiceTypeValues have human-displayable names, that are controlled by Rails I18n,
8
12
  # using standard Rails I18n pluralization forms, so for instance:
@@ -13,6 +17,10 @@ require 'yaml'
13
17
  #
14
18
  # Other languages may have more complex pluralization rules, but Umlaut at present only
15
19
  # looks up a plural form for 10 items, so 'other' is probably all that is used.
20
+ #
21
+ # If you want to load additional custom service type values from your own custom .yml file
22
+ # (say in a plugin), do `ServiceTypeValue.merge_yml_file!( filepath_to_yml )`, perhaps
23
+ # in an initializer.
16
24
  class ServiceTypeValue
17
25
  attr_accessor :name, :id
18
26
  attr_writer :display_name, :display_name_plural
@@ -25,10 +33,10 @@ class ServiceTypeValue
25
33
  end
26
34
  end
27
35
 
28
- def self.find(name)
29
- load_values! if values.nil?
36
+ def self.find(name)
30
37
  values[name.to_sym] or raise ArgumentError.new("No ServiceTypeValue found for #{name}")
31
38
  end
39
+
32
40
  def self.[](name)
33
41
  find(name)
34
42
  end
@@ -52,24 +60,30 @@ class ServiceTypeValue
52
60
 
53
61
  # Loads from config files, distro and local, into memory.
54
62
  def self.load_values!
55
- # Load in starting set of ServiceTypeValue, merge in local defines.
56
-
57
- service_type_values = YAML.load_file( @@distro_conf_file )
58
- local_overrides = File.exists?( @@local_conf_file ) ?
59
- YAML.load_file(@@local_conf_file) :
60
- nil
61
- # Merge in the params for each service type with possible
62
- # existing params.
63
- if ( local_overrides )
64
- local_overrides.each do |name, params|
65
- service_type_values[name] ||= {}
66
- service_type_values[name].merge!( params )
67
- end
68
- end
69
-
70
- self.values = {}
71
- service_type_values.each_pair do |name, hash|
72
- self.values[name.to_sym] = ServiceTypeValue.new(hash.merge(:name => name))
73
- end
63
+ # Load in starting set of ServiceTypeValue, merge in local defines.
64
+ self.merge_yml_file! @@distro_conf_file
65
+
66
+
67
+ if File.exists?( @@local_conf_file )
68
+ self.merge_yml_file! @@local_conf_file
69
+ end
70
+
71
+ end
72
+
73
+ def self.merge_hash!(definition_hash)
74
+ self.values ||= {}
75
+
76
+ definition_hash.each_pair do |name, value_hash|
77
+ self.values[name.to_sym] = ServiceTypeValue.new(value_hash.merge(:name => name))
78
+ end
74
79
  end
80
+
81
+ def self.merge_yml_file!(filepath)
82
+ self.merge_hash! YAML.load_file(filepath)
83
+ end
84
+
85
+ # We're doing this outside of a method body on purpose, when this
86
+ # file gets loaded, immediately load the default values.
87
+ self.load_values!
88
+
75
89
  end
data/lib/umlaut/routes.rb CHANGED
@@ -7,6 +7,8 @@ module Umlaut
7
7
  # app routes.rb, that line is generated into local app by Umlaut generator.
8
8
  # options include :only and :except to limit what route groups are generated.
9
9
  class Routes
10
+ class_attribute :default_route_sets
11
+ self.default_route_sets = [:root, :permalinks, :a_z, :resolve, :open_search, :link_router, :export_email, :resources, :search, :javascript, :feedback]
10
12
 
11
13
  def initialize(router, options ={})
12
14
  @router = router
@@ -19,6 +21,37 @@ module Umlaut
19
21
  end
20
22
  end
21
23
 
24
+
25
+ # Experimental functionality for a plugin to add routes that automatically
26
+ # will get applied by Umlaut::Routes
27
+ #
28
+ # Umlaut::Routes.register_routes( YourPlugin::RouteSets )
29
+ #
30
+ # Where YourPlugin::RouteSets is a module containing methods that defines
31
+ # routes similar to Umlaut::Routes::RouteSets below.
32
+ #
33
+ # If some methods included in the module are not route-defining methods,
34
+ # pass a second arg listing just those that are:
35
+ #
36
+ # Umlaut::Routes.register_routes(YourPlugin::RouteSets, [:magic, :underwater])
37
+ #
38
+ # All route_set_methods will be applied by default, but can be excluded
39
+ # on application with the standard Umlaut::RouteSet :only and :except args.
40
+ #
41
+ # This design is somewhat experimental, we'll see if it meets real world use cases
42
+ # with maintainable code.
43
+ def self.register_routes(module_obj, route_set_methods = nil)
44
+ if route_set_methods.nil?
45
+ # default to all methods defined in module
46
+ route_set_methods = module_obj.instance_methods
47
+ end
48
+
49
+ include module_obj
50
+ self.default_route_sets.concat route_set_methods
51
+
52
+ return self
53
+ end
54
+
22
55
  protected
23
56
 
24
57
  def add_routes &blk
@@ -30,10 +63,6 @@ module Umlaut
30
63
  (@options[:only] || default_route_sets) - (@options[:except] || []) + (@options[:admin] == true ? [:admin] : [])
31
64
  end
32
65
 
33
- def default_route_sets
34
- [:root, :permalinks, :a_z, :resolve, :open_search, :link_router, :export_email, :resources, :search, :javascript, :feedback]
35
- end
36
-
37
66
  module RouteSets
38
67
  # for now include root generation in Umlaut auto-generation
39
68
  def root
@@ -101,7 +130,7 @@ module Umlaut
101
130
  # legacy with the index, to keep old bookmarks working, needs to come first
102
131
  get 'link_router/index(/:id)' => "link_router#index"
103
132
 
104
- get 'link_router/:id' => "link_router#index"
133
+ get 'link_router/:id' => "link_router#index", :as => "link_router"
105
134
 
106
135
  end
107
136
  end