blacklight 6.18.0 → 6.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop_todo.yml +1 -1
  3. data/.travis.yml +5 -0
  4. data/Gemfile +1 -0
  5. data/VERSION +1 -1
  6. data/app/controllers/concerns/blacklight/bookmarks.rb +17 -3
  7. data/app/controllers/concerns/blacklight/catalog.rb +4 -2
  8. data/app/controllers/concerns/blacklight/controller.rb +10 -7
  9. data/app/controllers/concerns/blacklight/search_context.rb +5 -3
  10. data/app/controllers/concerns/blacklight/token_based_user.rb +3 -1
  11. data/app/models/blacklight/suggest_search.rb +3 -14
  12. data/app/models/concerns/blacklight/document.rb +3 -1
  13. data/app/models/concerns/blacklight/suggest/response.rb +5 -3
  14. data/app/presenters/blacklight/index_presenter.rb +3 -3
  15. data/blacklight.gemspec +5 -4
  16. data/lib/blacklight.rb +4 -4
  17. data/lib/blacklight/abstract_repository.rb +13 -1
  18. data/lib/blacklight/configuration.rb +2 -1
  19. data/lib/blacklight/configuration/fields.rb +46 -41
  20. data/lib/blacklight/engine.rb +2 -1
  21. data/lib/blacklight/solr/repository.rb +36 -3
  22. data/lib/generators/blacklight/assets_generator.rb +7 -2
  23. data/lib/generators/blacklight/install_generator.rb +1 -1
  24. data/lib/generators/blacklight/templates/catalog_controller.rb +3 -0
  25. data/lib/railties/blacklight.rake +11 -16
  26. data/spec/controllers/bookmarks_controller_spec.rb +35 -0
  27. data/spec/models/blacklight/configuration_spec.rb +81 -79
  28. data/spec/models/blacklight/solr/repository_spec.rb +11 -4
  29. data/spec/models/blacklight/suggest/response_spec.rb +5 -4
  30. data/spec/models/blacklight/suggest_search_spec.rb +6 -13
  31. data/spec/presenters/index_presenter_spec.rb +9 -0
  32. data/spec/spec_helper.rb +10 -6
  33. data/tasks/blacklight.rake +4 -4
  34. metadata +36 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 59d179acd38459b0540692e705b2c4835f31c022
4
- data.tar.gz: e3f02fe1b03842e4d80fe678435105064504c8c6
2
+ SHA256:
3
+ metadata.gz: f8c4e84017c1688f0bcd1f5d99438369b1ac18bda293369d65422d732b401755
4
+ data.tar.gz: 7c7dc8aaa1ceb8aa086ffdeecd6dd1c086952298f4a626c927df495f64958086
5
5
  SHA512:
6
- metadata.gz: f55802166972b36f29a5e687c4e42a323426b27a189134bc7940bf227e0532e6b183c57b4f3d539f92dd64a85ca8c915af68bd627e50c6560b9c07061a6141ad
7
- data.tar.gz: dec4137377509c2eebd25f4c63fb7302d9daf7e22d84e8bc7b0a8916999637c7d048b51964c7de8b7e8ebd5dcddb7739c7453c5304a612b9e045be9c9b3bc02d
6
+ metadata.gz: de725df92b158a47778ae9f7d0fe54b1055ca1679d68995d5dee0653cfb637bef524b3011d62fa2ec57289abae7f1e2158e38e160a32848112783531af0d1507
7
+ data.tar.gz: '02385cf07bd6d5c1296d8a5521acf481c42a6ec3046e3a2dbc5d21cba5a624dddec3d68e8f0cff8b885537a76b15a5d3ca7bf1729d167b64fadc5cad2e555e33'
data/.rubocop_todo.yml CHANGED
@@ -108,7 +108,7 @@ Metrics/MethodLength:
108
108
  # Offense count: 9
109
109
  # Configuration parameters: CountComments.
110
110
  Metrics/ModuleLength:
111
- Max: 208
111
+ Max: 211
112
112
  Exclude:
113
113
  - 'lib/blacklight/solr/search_builder_behavior.rb'
114
114
 
data/.travis.yml CHANGED
@@ -1,3 +1,6 @@
1
+ dist: trusty
2
+ addons:
3
+ chrome: stable
1
4
  language: ruby
2
5
  sudo: false
3
6
 
@@ -26,6 +29,7 @@ matrix:
26
29
  before_install:
27
30
  - gem update --system
28
31
  - gem install bundler
32
+ - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
29
33
 
30
34
  before_script:
31
35
  - if [[ "${RAILS_VERSION}" =~ ^4.2.* ]]; then perl -pi -e "s/ActiveRecord::Migration\[[\d\.]+\]/ActiveRecord::Migration/" db/migrate/*; fi
@@ -40,5 +44,6 @@ notifications:
40
44
 
41
45
  global_env:
42
46
  - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
47
+ - ENGINE_CART_RAILS_OPTIONS='--skip-git --skip-bundle --skip-listen --skip-spring --skip-yarn --skip-keeps --skip-action-cable --skip-coffee --skip-test'
43
48
 
44
49
  jdk: oraclejdk8
data/Gemfile CHANGED
@@ -37,6 +37,7 @@ else
37
37
  gem 'sass-rails', '>= 5.0'
38
38
  gem 'coffee-rails', '~> 4.1.0'
39
39
  gem 'json', '~> 1.8'
40
+ gem 'capybara', '~> 2.0'
40
41
  when /^4.[01]/
41
42
  gem 'sass-rails', '< 5.0'
42
43
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 6.18.0
1
+ 6.19.0
@@ -71,7 +71,7 @@ module Blacklight::Bookmarks
71
71
  # is simpler.
72
72
  def create
73
73
  @bookmarks = if params[:bookmarks]
74
- params[:bookmarks]
74
+ permit_bookmarks[:bookmarks]
75
75
  else
76
76
  [{ document_id: params[:id], document_type: blacklight_config.document_model.to_s }]
77
77
  end
@@ -103,9 +103,19 @@ module Blacklight::Bookmarks
103
103
  # Beware, :id is the Solr document_id, not the actual Bookmark id.
104
104
  # idempotent, as DELETE is supposed to be.
105
105
  def destroy
106
- bookmark = current_or_guest_user.bookmarks.find_by(document_id: params[:id], document_type: blacklight_config.document_model.to_s)
106
+ @bookmarks =
107
+ if params[:bookmarks]
108
+ permit_bookmarks[:bookmarks]
109
+ else
110
+ [{ document_id: params[:id], document_type: blacklight_config.document_model.to_s }]
111
+ end
107
112
 
108
- if bookmark && bookmark.delete && bookmark.destroyed?
113
+ success = @bookmarks.all? do |bookmark|
114
+ bookmark = current_or_guest_user.bookmarks.find_by(bookmark)
115
+ bookmark && bookmark.delete && bookmark.destroyed?
116
+ end
117
+
118
+ if success
109
119
  if request.xhr?
110
120
  render(json: { bookmarks: { count: current_or_guest_user.bookmarks.count }})
111
121
  elsif respond_to? :redirect_back
@@ -144,4 +154,8 @@ module Blacklight::Bookmarks
144
154
  def start_new_search_session?
145
155
  action_name == "index"
146
156
  end
157
+
158
+ def permit_bookmarks
159
+ params.permit(bookmarks: [:document_id, :document_type])
160
+ end
147
161
  end
@@ -9,9 +9,11 @@ module Blacklight::Catalog
9
9
  # The following code is executed when someone includes blacklight::catalog in their
10
10
  # own controller.
11
11
  included do
12
- helper_method :sms_mappings, :has_search_parameters?
12
+ if respond_to? :helper_method
13
+ helper_method :sms_mappings, :has_search_parameters?
14
+ end
13
15
 
14
- helper Blacklight::Facet
16
+ helper Blacklight::Facet if respond_to? :helper
15
17
 
16
18
  # When an action raises Blacklight::Exceptions::RecordNotFound, handle
17
19
  # the exception appropriately.
@@ -8,23 +8,26 @@ module Blacklight::Controller
8
8
 
9
9
  included do
10
10
  include Blacklight::SearchFields
11
- helper Blacklight::SearchFields
11
+ helper Blacklight::SearchFields if respond_to? :helper
12
12
 
13
13
  include ActiveSupport::Callbacks
14
14
 
15
15
  # now in application.rb file under config.filter_parameters
16
16
  # filter_parameter_logging :password, :password_confirmation
17
- helper_method :current_user_session, :current_user, :current_or_guest_user
18
17
  after_action :discard_flash_if_xhr
19
18
 
20
19
  # handle basic authorization exception with #access_denied
21
20
  rescue_from Blacklight::Exceptions::AccessDenied, :with => :access_denied
22
21
 
23
- # extra head content
24
- helper_method :has_user_authentication_provider?
25
- helper_method :blacklight_config, :blacklight_configuration_context
26
- helper_method :search_action_url, :search_action_path, :search_facet_url, :search_facet_path
27
- helper_method :search_state
22
+ if respond_to? :helper_method
23
+ helper_method :current_user_session, :current_user, :current_or_guest_user
24
+
25
+ # extra head content
26
+ helper_method :has_user_authentication_provider?
27
+ helper_method :blacklight_config, :blacklight_configuration_context
28
+ helper_method :search_action_url, :search_action_path, :search_facet_path
29
+ helper_method :search_state
30
+ end
28
31
 
29
32
  # Specify which class to use for the search state. You can subclass SearchState if you
30
33
  # want to override any of the methods (e.g. SearchState#url_for_document)
@@ -2,10 +2,12 @@
2
2
  module Blacklight::SearchContext
3
3
  extend ActiveSupport::Concern
4
4
 
5
- # The following code is executed when someone includes blacklight::catalog::search_session in their
5
+ # The following code is executed when someone includes Blacklight::Catalog::SearchSession in their
6
6
  # own controller.
7
- included do
8
- helper_method :current_search_session, :search_session
7
+ included do
8
+ if respond_to? :helper_method
9
+ helper_method :current_search_session, :search_session
10
+ end
9
11
  end
10
12
 
11
13
  module ClassMethods
@@ -3,7 +3,9 @@ module Blacklight::TokenBasedUser
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- helper_method :encrypt_user_id
6
+ if respond_to? :helper_method
7
+ helper_method :encrypt_user_id
8
+ end
7
9
 
8
10
  rescue_from Blacklight::Exceptions::ExpiredSessionToken do
9
11
  head :unauthorized
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Blacklight
3
4
  class SuggestSearch
4
5
  attr_reader :request_params, :repository
5
6
 
6
7
  ##
7
8
  # @param [Hash] params
9
+ # @param [Blacklight::AbstractRepository] repository
8
10
  def initialize(params, repository)
9
11
  @request_params = { q: params[:q] }
10
12
  @repository = repository
@@ -15,20 +17,7 @@ module Blacklight
15
17
  # Blacklight::Suggest::Response
16
18
  # @return [Blacklight::Suggest::Response]
17
19
  def suggestions
18
- Blacklight::Suggest::Response.new suggest_results, request_params, suggest_handler_path
19
- end
20
-
21
- ##
22
- # Query the suggest handler using RSolr::Client::send_and_receive
23
- # @return [RSolr::HashWithResponse]
24
- def suggest_results
25
- repository.connection.send_and_receive(suggest_handler_path, params: request_params)
26
- end
27
-
28
- ##
29
- # @return [String]
30
- def suggest_handler_path
31
- repository.blacklight_config.autocomplete_path
20
+ repository.suggestions(request_params)
32
21
  end
33
22
  end
34
23
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
- ##
2
+
3
+ require 'globalid'
4
+
3
5
  ##
4
6
  # = Introduction
5
7
  # Blacklight::Document is the module with logic for a class representing
@@ -2,17 +2,19 @@
2
2
  module Blacklight
3
3
  module Suggest
4
4
  class Response
5
- attr_reader :response, :request_params, :suggest_path
5
+ attr_reader :response, :request_params, :suggest_path, :suggester_name
6
6
 
7
7
  ##
8
8
  # Creates a suggest response
9
9
  # @param [RSolr::HashWithResponse] response
10
10
  # @param [Hash] request_params
11
11
  # @param [String] suggest_path
12
- def initialize(response, request_params, suggest_path)
12
+ # @param [String] suggester_name
13
+ def initialize(response, request_params, suggest_path, suggester_name)
13
14
  @response = response
14
15
  @request_params = request_params
15
16
  @suggest_path = suggest_path
17
+ @suggester_name = suggester_name
16
18
  end
17
19
 
18
20
  ##
@@ -20,7 +22,7 @@ module Blacklight
20
22
  # present
21
23
  # @return [Array]
22
24
  def suggestions
23
- response.try(:[], suggest_path).try(:[], 'mySuggester').try(:[], request_params[:q]).try(:[], 'suggestions') || []
25
+ (response.try(:[], suggest_path).try(:[], suggester_name).try(:[], request_params[:q]).try(:[], 'suggestions') || []).uniq
24
26
  end
25
27
  end
26
28
  end
@@ -53,10 +53,10 @@ module Blacklight
53
53
  # @option options [String] :value
54
54
  def field_value field_or_name, options = {}
55
55
  field = case field_or_name
56
- when String
57
- Deprecation.warn(self, "You provided a String value to IndexPresenter#field_value " \
56
+ when String, Symbol
57
+ Deprecation.warn(self, "You provided a String or Symbol value to IndexPresenter#field_value " \
58
58
  "Provide a Blacklight::Configuration::Field instead. field_value() will not accept " \
59
- "strings in Blacklight 7")
59
+ "strings or symbols in Blacklight 7")
60
60
  field_config(field_or_name)
61
61
  else
62
62
  field_or_name
data/blacklight.gemspec CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
27
27
 
28
28
  s.add_dependency "rails", ">= 4.2", "< 6"
29
29
  s.add_dependency "globalid"
30
- s.add_dependency "jbuilder"
30
+ s.add_dependency "jbuilder", '~> 2.7'
31
31
  s.add_dependency "nokogiri", "~>1.6" # XML Parser
32
32
  s.add_dependency "kaminari", ">= 0.15" # the pagination (page 1,2,3, etc..) of our search results
33
33
  s.add_dependency "rsolr", ">= 1.0.6", "< 3" # Library for interacting with rSolr.
@@ -39,9 +39,10 @@ Gem::Specification.new do |s|
39
39
  s.add_development_dependency "rspec-rails", "~> 3.5"
40
40
  s.add_development_dependency "rspec-its"
41
41
  s.add_development_dependency "rspec-collection_matchers", ">= 1.0"
42
- s.add_development_dependency "capybara", '~> 2.6'
43
- s.add_development_dependency "poltergeist"
44
- s.add_development_dependency 'engine_cart', '~> 1.0'
42
+ s.add_development_dependency "capybara", '>= 2', '< 4'
43
+ s.add_development_dependency 'chromedriver-helper', '< 2.0.0' # 2.1.0 is causing "Unable to find chromedriver" on Travis
44
+ s.add_development_dependency "selenium-webdriver", '>= 3.13.1'
45
+ s.add_development_dependency 'engine_cart', '~> 1.2'
45
46
  s.add_development_dependency "equivalent-xml"
46
47
  s.add_development_dependency "coveralls"
47
48
  s.add_development_dependency "simplecov"
data/lib/blacklight.rb CHANGED
@@ -3,6 +3,7 @@ require 'kaminari'
3
3
  require 'deprecation'
4
4
  require 'blacklight/utils'
5
5
  require 'active_support/hash_with_indifferent_access'
6
+ require 'jbuilder'
6
7
 
7
8
  module Blacklight
8
9
  autoload :AbstractRepository, 'blacklight/abstract_repository'
@@ -105,17 +106,16 @@ module Blacklight
105
106
  @logger = logger
106
107
  end
107
108
 
108
- #############
109
+ #############
109
110
  # Methods for figuring out path to BL plugin, and then locate various files
110
111
  # either in the app itself or defaults in the plugin -- whether you are running
111
112
  # from the plugin itself or from an actual app using te plugin.
112
113
  # In a seperate module so it can be used by both Blacklight class, and
113
- # by rake tasks without loading the whole Rails environment.
114
+ # by rake tasks without loading the whole Rails environment.
114
115
  #############
115
-
116
+
116
117
  # returns the full path the the blacklight plugin installation
117
118
  def self.root
118
119
  @root ||= File.expand_path(File.dirname(File.dirname(__FILE__)))
119
120
  end
120
-
121
121
  end
@@ -32,7 +32,19 @@ module Blacklight
32
32
  raise NotImplementedError
33
33
  end
34
34
 
35
- protected
35
+ # Query the fields that exist from the index
36
+ # @return [Hash]
37
+ def reflect_fields
38
+ raise NotImplementedError
39
+ end
40
+
41
+ ##
42
+ # Is the repository in a working state?
43
+ def ping
44
+ raise NotImplementedError
45
+ end
46
+
47
+ private
36
48
 
37
49
  def connection_config
38
50
  blacklight_config.connection_config
@@ -142,7 +142,8 @@ module Blacklight
142
142
  default_more_limit: 20,
143
143
  # proc for determining whether the session is a crawler/bot
144
144
  # ex.: crawler_detector: lambda { |req| req.env['HTTP_USER_AGENT'] =~ /bot/ }
145
- crawler_detector: nil
145
+ crawler_detector: nil,
146
+ autocomplete_suggester: 'mySuggester'
146
147
  }
147
148
  end
148
149
  end
@@ -5,6 +5,8 @@ module Blacklight
5
5
  # solr fields configuration
6
6
  module Fields
7
7
  extend ActiveSupport::Concern
8
+ extend Deprecation
9
+ self.deprecation_horizon = 'blacklight version 8.0.0'
8
10
 
9
11
  module ClassMethods
10
12
  # Add a configuration block for a collection of solr fields
@@ -20,7 +22,7 @@ module Blacklight
20
22
  class #{key.camelcase} < #{base_class_name}; end
21
23
  END_EVAL
22
24
  end
23
-
25
+
24
26
  class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
25
27
  def add_#{key}(*args, &block)
26
28
  add_blacklight_field("#{key}", *args, &block)
@@ -32,7 +34,7 @@ module Blacklight
32
34
  # Add a solr field configuration to the given configuration key
33
35
  #
34
36
  # The recommended and strongly encouraged format is a field name, configuration pair, e.g.:
35
- # add_blacklight_field :index_field, 'format', :label => 'Format'
37
+ # add_blacklight_field :index_field, 'format', :label => 'Format'
36
38
  #
37
39
  # Alternative formats include:
38
40
  #
@@ -56,7 +58,7 @@ module Blacklight
56
58
  # field.field = 'format'
57
59
  # field.label = 'Format'
58
60
  # end
59
- #
61
+ #
60
62
  # * a configuration hash:
61
63
  #
62
64
  # @overload add_blacklight_field(config_key, options)
@@ -64,8 +66,8 @@ module Blacklight
64
66
  # @param [Hash] options
65
67
  #
66
68
  # add_blacklight_field :index_field, :field => 'format', :label => 'Format'
67
- #
68
- # * a Field instance:
69
+ #
70
+ # * a Field instance:
69
71
  #
70
72
  # @overload add_blacklight_field(config_key, field)
71
73
  # @param [Symbol] config_key
@@ -74,7 +76,7 @@ module Blacklight
74
76
  #
75
77
  # add_blacklight_field :index_field, IndexField.new(:field => 'format', :label => 'Format')
76
78
  #
77
- # * an array of hashes:
79
+ # * an array of hashes:
78
80
  #
79
81
  # @overload add_blacklight_field(config_key, fields)
80
82
  # @param [Symbol] config_key
@@ -102,31 +104,14 @@ module Blacklight
102
104
 
103
105
  # look up any dynamic fields
104
106
  if field_config.match
105
-
106
- salient_fields = luke_fields.select do |k,v|
107
- k =~ field_config.match
108
- end
109
-
110
- salient_fields.each do |field, luke_config|
111
- config = field_config.dup
112
- config.match = nil
113
- config.field = field
114
- config.key = field
115
-
116
- if self[config_key.pluralize][ config.key ]
117
- self[config_key.pluralize][ config.key ] = config.merge(self[config_key.pluralize][ config.key ])
118
- else
119
- add_blacklight_field(config_key, config, &block)
120
- end
121
- end
122
-
107
+ handle_matching_fields(config_key, field_config, &block)
123
108
  return
124
109
  end
125
-
110
+
126
111
  if block_given?
127
112
  yield field_config
128
113
  end
129
-
114
+
130
115
  field_config.normalize!(self)
131
116
  field_config.validate!
132
117
 
@@ -137,27 +122,47 @@ module Blacklight
137
122
 
138
123
  protected
139
124
 
140
- def luke_fields
141
- if @table[:luke_fields] == false
125
+ ##
126
+ # Using reflection into the index, add any fields in the index that match the field_config
127
+ def handle_matching_fields(config_key, field_config, &block)
128
+ salient_fields = reflected_fields.select do |k, _v|
129
+ k =~ field_config.match
130
+ end
131
+
132
+ salient_fields.each_key do |field|
133
+ config = field_config.dup
134
+ config.match = nil
135
+ config.field = field
136
+ config.key = field
137
+ if self[config_key.pluralize][config.key]
138
+ self[config_key.pluralize][config.key] = config.merge(self[config_key.pluralize][config.key])
139
+ else
140
+ add_blacklight_field(config_key, config, &block)
141
+ end
142
+ end
143
+ end
144
+
145
+ def reflected_fields
146
+ if @table[:reflected_fields] == false
142
147
  return nil
143
148
  end
144
149
 
145
- @table[:luke_fields] ||= Rails.cache.fetch("blacklight_configuration/admin/luke", expires_in: 1.hour) do
150
+ @table[:reflected_fields] ||= Rails.cache.fetch("blacklight_configuration/admin/reflected_fields", expires_in: 1.hour) do
146
151
  begin
147
- if repository_class <= Blacklight::Solr::Repository
148
- repository = repository_class.new(self)
149
- repository.send_and_receive('admin/luke', params: { fl: '*', 'json.nl' => 'map' })['fields']
150
- end
152
+ repository = repository_class.new(self)
153
+ repository.reflect_fields
151
154
  rescue => e
152
155
  Blacklight.logger.warn "Error retrieving field metadata: #{e}"
153
156
  false
154
157
  end
155
158
  end
156
159
 
157
- @table[:luke_fields] || {}
160
+ @table[:reflected_fields] || {}
158
161
  end
162
+ alias luke_fields reflected_fields
163
+ deprecation_deprecate luke_fields: 'use reflected_fields instead'
159
164
 
160
- # Add a solr field by a solr field name and hash
165
+ # Add a solr field by a solr field name and hash
161
166
  def field_config_from_key_and_hash config_key, field_name, field_or_hash = {}
162
167
  field_config = field_config_from_field_or_hash(config_key, field_or_hash)
163
168
  field_config.key = field_name
@@ -166,7 +171,7 @@ module Blacklight
166
171
 
167
172
  # Add multiple solr fields using a hash or Field instance
168
173
  def field_config_from_array config_key, array_of_fields_or_hashes, &block
169
- array_of_fields_or_hashes.map do |field_or_hash|
174
+ array_of_fields_or_hashes.map do |field_or_hash|
170
175
  add_blacklight_field(config_key, field_or_hash, &block)
171
176
  end
172
177
  end
@@ -180,16 +185,16 @@ module Blacklight
180
185
  # and makes it into a specific config OpenStruct, like
181
186
  # FacetField or SearchField. Or if the param already was
182
187
  # one, that's cool. Or if the param is nil, make
183
- # an empty one. Second argument is an actual class object.
188
+ # an empty one. Second argument is an actual class object.
184
189
  def hash_arg_to_config(hash_arg, klass)
185
190
  case hash_arg
186
- when Hash
191
+ when Hash
187
192
  klass.new(hash_arg)
188
- when NilClass
193
+ when NilClass
189
194
  klass.new
190
- else
195
+ else
191
196
  # this assumes it already is an element of klass, or acts like one,
192
- # if not something bad will happen later, that's your problem.
197
+ # if not something bad will happen later, that's your problem.
193
198
  hash_arg
194
199
  end
195
200
  end