haveapi 0.20.0 → 0.21.0
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.
- checksums.yaml +4 -4
 - data/Gemfile +1 -1
 - data/Rakefile +6 -6
 - data/haveapi.gemspec +13 -13
 - data/lib/haveapi/action.rb +140 -158
 - data/lib/haveapi/action_state.rb +2 -6
 - data/lib/haveapi/actions/default.rb +8 -10
 - data/lib/haveapi/api.rb +2 -1
 - data/lib/haveapi/authentication/base.rb +5 -8
 - data/lib/haveapi/authentication/basic/provider.rb +4 -5
 - data/lib/haveapi/authentication/chain.rb +19 -17
 - data/lib/haveapi/authentication/oauth2/config.rb +12 -32
 - data/lib/haveapi/authentication/oauth2/provider.rb +20 -30
 - data/lib/haveapi/authentication/oauth2/revoke_endpoint.rb +1 -2
 - data/lib/haveapi/authentication/token/action_config.rb +5 -3
 - data/lib/haveapi/authentication/token/config.rb +5 -5
 - data/lib/haveapi/authentication/token/provider.rb +33 -37
 - data/lib/haveapi/authorization.rb +5 -4
 - data/lib/haveapi/client_example.rb +11 -14
 - data/lib/haveapi/client_examples/curl.rb +37 -37
 - data/lib/haveapi/client_examples/fs_client.rb +29 -31
 - data/lib/haveapi/client_examples/http.rb +35 -36
 - data/lib/haveapi/client_examples/js_client.rb +62 -63
 - data/lib/haveapi/client_examples/php_client.rb +77 -76
 - data/lib/haveapi/client_examples/ruby_cli.rb +30 -30
 - data/lib/haveapi/client_examples/ruby_client.rb +26 -26
 - data/lib/haveapi/common.rb +3 -4
 - data/lib/haveapi/context.rb +11 -10
 - data/lib/haveapi/example.rb +9 -4
 - data/lib/haveapi/example_list.rb +2 -2
 - data/lib/haveapi/exceptions.rb +1 -1
 - data/lib/haveapi/extensions/action_exceptions.rb +2 -2
 - data/lib/haveapi/extensions/base.rb +1 -3
 - data/lib/haveapi/extensions/exception_mailer.rb +260 -257
 - data/lib/haveapi/hooks.rb +40 -39
 - data/lib/haveapi/metadata.rb +1 -1
 - data/lib/haveapi/model_adapter.rb +16 -27
 - data/lib/haveapi/model_adapters/active_record.rb +59 -69
 - data/lib/haveapi/output_formatter.rb +7 -7
 - data/lib/haveapi/output_formatters/base.rb +2 -4
 - data/lib/haveapi/parameters/resource.rb +7 -7
 - data/lib/haveapi/parameters/typed.rb +6 -9
 - data/lib/haveapi/params.rb +38 -45
 - data/lib/haveapi/resource.rb +8 -8
 - data/lib/haveapi/resources/action_state.rb +11 -19
 - data/lib/haveapi/server.rb +102 -107
 - data/lib/haveapi/spec/api_response.rb +1 -1
 - data/lib/haveapi/spec/helpers.rb +1 -1
 - data/lib/haveapi/spec/mock_action.rb +11 -10
 - data/lib/haveapi/spec/spec_methods.rb +9 -8
 - data/lib/haveapi/tasks/yard.rb +2 -2
 - data/lib/haveapi/types.rb +0 -3
 - data/lib/haveapi/validator.rb +6 -3
 - data/lib/haveapi/validator_chain.rb +9 -8
 - data/lib/haveapi/validators/acceptance.rb +6 -6
 - data/lib/haveapi/validators/confirmation.rb +2 -3
 - data/lib/haveapi/validators/exclusion.rb +1 -1
 - data/lib/haveapi/validators/format.rb +1 -1
 - data/lib/haveapi/validators/inclusion.rb +1 -1
 - data/lib/haveapi/validators/length.rb +12 -11
 - data/lib/haveapi/validators/numericality.rb +14 -13
 - data/lib/haveapi/validators/presence.rb +4 -3
 - data/lib/haveapi/version.rb +2 -2
 - data/lib/haveapi.rb +2 -3
 - data/spec/.rubocop.yml +4 -0
 - data/spec/action/dsl_spec.rb +18 -18
 - data/spec/authorization_spec.rb +8 -8
 - data/spec/common_spec.rb +2 -1
 - data/spec/documentation_spec.rb +2 -9
 - data/spec/envelope_spec.rb +2 -2
 - data/spec/hooks_spec.rb +12 -12
 - data/spec/parameters/typed_spec.rb +6 -6
 - data/spec/params_spec.rb +22 -24
 - data/spec/resource_spec.rb +5 -7
 - data/spec/spec_helper.rb +0 -1
 - data/spec/validators/acceptance_spec.rb +1 -1
 - data/spec/validators/confirmation_spec.rb +5 -5
 - data/spec/validators/exclusion_spec.rb +3 -3
 - data/spec/validators/format_spec.rb +2 -2
 - data/spec/validators/inclusion_spec.rb +4 -4
 - data/spec/validators/length_spec.rb +23 -23
 - data/spec/validators/numericality_spec.rb +13 -13
 - data/spec/validators/presence_spec.rb +3 -3
 - metadata +49 -48
 
    
        data/lib/haveapi/hooks.rb
    CHANGED
    
    | 
         @@ -77,7 +77,7 @@ module HaveAPI 
     | 
|
| 
       77 
77 
     | 
    
         
             
              #   p MyClass.call_hooks(:myhook, args: [1, 2, 3], initial: {counter: 0})
         
     | 
| 
       78 
78 
     | 
    
         
             
              #   => {:counter=>5}
         
     | 
| 
       79 
79 
     | 
    
         
             
              module Hooks
         
     | 
| 
       80 
     | 
    
         
            -
                INSTANCE_VARIABLE = '@_haveapi_hooks'
         
     | 
| 
      
 80 
     | 
    
         
            +
                INSTANCE_VARIABLE = '@_haveapi_hooks'.freeze
         
     | 
| 
       81 
81 
     | 
    
         | 
| 
       82 
82 
     | 
    
         
             
                # Register a hook defined by `klass` with `name`.
         
     | 
| 
       83 
83 
     | 
    
         
             
                # @param klass [Class]  an instance of Class, that is class name, not it's instance
         
     | 
| 
         @@ -116,7 +116,7 @@ module HaveAPI 
     | 
|
| 
       116 
116 
     | 
    
         
             
                    instance.instance_variable_set(INSTANCE_VARIABLE, hooks)
         
     | 
| 
       117 
117 
     | 
    
         
             
                  end
         
     | 
| 
       118 
118 
     | 
    
         | 
| 
       119 
     | 
    
         
            -
                  hooks[name] ||= {listeners: []}
         
     | 
| 
      
 119 
     | 
    
         
            +
                  hooks[name] ||= { listeners: [] }
         
     | 
| 
       120 
120 
     | 
    
         
             
                  hooks[name][:listeners] << block
         
     | 
| 
       121 
121 
     | 
    
         
             
                end
         
     | 
| 
       122 
122 
     | 
    
         | 
| 
         @@ -143,36 +143,37 @@ module HaveAPI 
     | 
|
| 
       143 
143 
     | 
    
         
             
                # @param initial [Hash] initial return value
         
     | 
| 
       144 
144 
     | 
    
         
             
                # @param instance [Boolean] call instance hooks or not; nil means auto-detect
         
     | 
| 
       145 
145 
     | 
    
         
             
                def self.call_for(
         
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
             
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
      
 146 
     | 
    
         
            +
                  klass,
         
     | 
| 
      
 147 
     | 
    
         
            +
                  name,
         
     | 
| 
      
 148 
     | 
    
         
            +
                  where = nil,
         
     | 
| 
      
 149 
     | 
    
         
            +
                  args: [],
         
     | 
| 
      
 150 
     | 
    
         
            +
                  kwargs: {},
         
     | 
| 
      
 151 
     | 
    
         
            +
                  initial: {},
         
     | 
| 
      
 152 
     | 
    
         
            +
                  instance: nil
         
     | 
| 
       153 
153 
     | 
    
         
             
                )
         
     | 
| 
       154 
154 
     | 
    
         
             
                  classified = hook_classify(klass)
         
     | 
| 
       155 
155 
     | 
    
         | 
| 
       156 
     | 
    
         
            -
                  if (instance.nil? && !classified.is_a?(Class)) || instance
         
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
      
 156 
     | 
    
         
            +
                  all_hooks = if (instance.nil? && !classified.is_a?(Class)) || instance
         
     | 
| 
      
 157 
     | 
    
         
            +
                                klass.instance_variable_get(INSTANCE_VARIABLE)
         
     | 
| 
       158 
158 
     | 
    
         | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
       161 
     | 
    
         
            -
             
     | 
| 
      
 159 
     | 
    
         
            +
                              else
         
     | 
| 
      
 160 
     | 
    
         
            +
                                @hooks[classified]
         
     | 
| 
      
 161 
     | 
    
         
            +
                              end
         
     | 
| 
       162 
162 
     | 
    
         | 
| 
       163 
163 
     | 
    
         
             
                  catch(:stop) do
         
     | 
| 
       164 
164 
     | 
    
         
             
                    return initial unless all_hooks
         
     | 
| 
       165 
165 
     | 
    
         
             
                    return initial unless all_hooks[name]
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
       166 
167 
     | 
    
         
             
                    hooks = all_hooks[name][:listeners]
         
     | 
| 
       167 
168 
     | 
    
         
             
                    return initial unless hooks
         
     | 
| 
       168 
169 
     | 
    
         | 
| 
       169 
170 
     | 
    
         
             
                    hooks.each do |hook|
         
     | 
| 
       170 
     | 
    
         
            -
                      if where
         
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
      
 171 
     | 
    
         
            +
                      ret = if where
         
     | 
| 
      
 172 
     | 
    
         
            +
                              where.instance_exec(initial, *args, **kwargs, &hook)
         
     | 
| 
       172 
173 
     | 
    
         | 
| 
       173 
     | 
    
         
            -
             
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
             
     | 
| 
      
 174 
     | 
    
         
            +
                            else
         
     | 
| 
      
 175 
     | 
    
         
            +
                              hook.call(initial, *args, **kwargs)
         
     | 
| 
      
 176 
     | 
    
         
            +
                            end
         
     | 
| 
       176 
177 
     | 
    
         | 
| 
       177 
178 
     | 
    
         
             
                      initial.update(ret) if ret
         
     | 
| 
       178 
179 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -195,60 +196,60 @@ module HaveAPI 
     | 
|
| 
       195 
196 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
       196 
197 
     | 
    
         
             
                  # Register a hook named `name`.
         
     | 
| 
       197 
198 
     | 
    
         
             
                  def has_hook(name, opts = {})
         
     | 
| 
       198 
     | 
    
         
            -
                    Hooks.register_hook( 
     | 
| 
      
 199 
     | 
    
         
            +
                    Hooks.register_hook(to_s, name, opts)
         
     | 
| 
       199 
200 
     | 
    
         
             
                  end
         
     | 
| 
       200 
201 
     | 
    
         | 
| 
       201 
202 
     | 
    
         
             
                  # Connect `block` to registered hook with `name`.
         
     | 
| 
       202 
     | 
    
         
            -
                  def connect_hook(name, & 
     | 
| 
       203 
     | 
    
         
            -
                    Hooks.connect_hook( 
     | 
| 
      
 203 
     | 
    
         
            +
                  def connect_hook(name, &)
         
     | 
| 
      
 204 
     | 
    
         
            +
                    Hooks.connect_hook(to_s, name, &)
         
     | 
| 
       204 
205 
     | 
    
         
             
                  end
         
     | 
| 
       205 
206 
     | 
    
         | 
| 
       206 
207 
     | 
    
         
             
                  # Call all hooks for `name`. see {Hooks.call_for}.
         
     | 
| 
       207 
     | 
    
         
            -
                  def call_hooks( 
     | 
| 
       208 
     | 
    
         
            -
                    Hooks.call_for( 
     | 
| 
      
 208 
     | 
    
         
            +
                  def call_hooks(*, **)
         
     | 
| 
      
 209 
     | 
    
         
            +
                    Hooks.call_for(to_s, *, **)
         
     | 
| 
       209 
210 
     | 
    
         
             
                  end
         
     | 
| 
       210 
211 
     | 
    
         
             
                end
         
     | 
| 
       211 
212 
     | 
    
         | 
| 
       212 
213 
     | 
    
         
             
                module InstanceMethods
         
     | 
| 
       213 
214 
     | 
    
         
             
                  # Call all instance and class hooks.
         
     | 
| 
       214 
     | 
    
         
            -
                  def call_hooks_for( 
     | 
| 
       215 
     | 
    
         
            -
                    ret = call_instance_hooks_for( 
     | 
| 
      
 215 
     | 
    
         
            +
                  def call_hooks_for(*, **kwargs)
         
     | 
| 
      
 216 
     | 
    
         
            +
                    ret = call_instance_hooks_for(*, **kwargs)
         
     | 
| 
       216 
217 
     | 
    
         | 
| 
       217 
218 
     | 
    
         
             
                    kwargs[:initial] = ret
         
     | 
| 
       218 
     | 
    
         
            -
                    call_class_hooks_for( 
     | 
| 
      
 219 
     | 
    
         
            +
                    call_class_hooks_for(*, **kwargs)
         
     | 
| 
       219 
220 
     | 
    
         
             
                  end
         
     | 
| 
       220 
221 
     | 
    
         | 
| 
       221 
222 
     | 
    
         
             
                  # Call only instance hooks.
         
     | 
| 
       222 
223 
     | 
    
         
             
                  def call_instance_hooks_for(name, where = nil, args: [], kwargs: {}, initial: {})
         
     | 
| 
       223 
     | 
    
         
            -
                    Hooks.call_for(self, name, where, args 
     | 
| 
      
 224 
     | 
    
         
            +
                    Hooks.call_for(self, name, where, args:, kwargs:, initial:)
         
     | 
| 
       224 
225 
     | 
    
         
             
                  end
         
     | 
| 
       225 
226 
     | 
    
         | 
| 
       226 
227 
     | 
    
         
             
                  # Call only class hooks.
         
     | 
| 
       227 
     | 
    
         
            -
                  def call_class_hooks_for(name, where 
     | 
| 
       228 
     | 
    
         
            -
                    Hooks.call_for(self.class, name, where, args 
     | 
| 
      
 228 
     | 
    
         
            +
                  def call_class_hooks_for(name, where = nil, args: [], kwargs: {}, initial: {})
         
     | 
| 
      
 229 
     | 
    
         
            +
                    Hooks.call_for(self.class, name, where, args:, kwargs:, initial:)
         
     | 
| 
       229 
230 
     | 
    
         
             
                  end
         
     | 
| 
       230 
231 
     | 
    
         | 
| 
       231 
232 
     | 
    
         
             
                  # Call hooks for different `klass`.
         
     | 
| 
       232 
     | 
    
         
            -
                  def call_hooks_as_for(klass,  
     | 
| 
       233 
     | 
    
         
            -
                    ret = call_instance_hooks_as_for(klass,  
     | 
| 
      
 233 
     | 
    
         
            +
                  def call_hooks_as_for(klass, *, **kwargs)
         
     | 
| 
      
 234 
     | 
    
         
            +
                    ret = call_instance_hooks_as_for(klass, *, **kwargs)
         
     | 
| 
       234 
235 
     | 
    
         | 
| 
       235 
236 
     | 
    
         
             
                    kwargs[:initial] = ret
         
     | 
| 
       236 
     | 
    
         
            -
                    call_class_hooks_as_for(klass.class,  
     | 
| 
      
 237 
     | 
    
         
            +
                    call_class_hooks_as_for(klass.class, *, **kwargs)
         
     | 
| 
       237 
238 
     | 
    
         
             
                  end
         
     | 
| 
       238 
239 
     | 
    
         | 
| 
       239 
240 
     | 
    
         
             
                  # Call only instance hooks for different `klass`.
         
     | 
| 
       240 
     | 
    
         
            -
                  def call_instance_hooks_as_for(klass,  
     | 
| 
       241 
     | 
    
         
            -
                    Hooks.call_for(klass,  
     | 
| 
      
 241 
     | 
    
         
            +
                  def call_instance_hooks_as_for(klass, *, **)
         
     | 
| 
      
 242 
     | 
    
         
            +
                    Hooks.call_for(klass, *, **)
         
     | 
| 
       242 
243 
     | 
    
         
             
                  end
         
     | 
| 
       243 
244 
     | 
    
         | 
| 
       244 
245 
     | 
    
         
             
                  # Call only class hooks for different `klass`.
         
     | 
| 
       245 
     | 
    
         
            -
                  def call_class_hooks_as_for(klass,  
     | 
| 
       246 
     | 
    
         
            -
                    Hooks.call_for(klass,  
     | 
| 
      
 246 
     | 
    
         
            +
                  def call_class_hooks_as_for(klass, *, **)
         
     | 
| 
      
 247 
     | 
    
         
            +
                    Hooks.call_for(klass, *, **)
         
     | 
| 
       247 
248 
     | 
    
         
             
                  end
         
     | 
| 
       248 
249 
     | 
    
         | 
| 
       249 
250 
     | 
    
         
             
                  # Connect instance level hook `name` to `block`.
         
     | 
| 
       250 
     | 
    
         
            -
                  def connect_hook(name, & 
     | 
| 
       251 
     | 
    
         
            -
                    Hooks.connect_instance_hook(self, name, & 
     | 
| 
      
 251 
     | 
    
         
            +
                  def connect_hook(name, &)
         
     | 
| 
      
 252 
     | 
    
         
            +
                    Hooks.connect_instance_hook(self, name, &)
         
     | 
| 
       252 
253 
     | 
    
         
             
                  end
         
     | 
| 
       253 
254 
     | 
    
         
             
                end
         
     | 
| 
       254 
255 
     | 
    
         | 
    
        data/lib/haveapi/metadata.rb
    CHANGED
    
    
| 
         @@ -14,38 +14,37 @@ module HaveAPI 
     | 
|
| 
       14 
14 
     | 
    
         
             
                  # Every model adapter must register itself using this method.
         
     | 
| 
       15 
15 
     | 
    
         
             
                  def register
         
     | 
| 
       16 
16 
     | 
    
         
             
                    ModelAdapter.adapters ||= []
         
     | 
| 
       17 
     | 
    
         
            -
                    ModelAdapter.adapters << Kernel.const_get( 
     | 
| 
      
 17 
     | 
    
         
            +
                    ModelAdapter.adapters << Kernel.const_get(to_s)
         
     | 
| 
       18 
18 
     | 
    
         
             
                  end
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
20 
     | 
    
         
             
                  # Returns an adapter suitable for `layout` and `obj`.
         
     | 
| 
       21 
21 
     | 
    
         
             
                  # Adapters are iterated over and the first to return true to handle?()
         
     | 
| 
       22 
22 
     | 
    
         
             
                  # is returned.
         
     | 
| 
       23 
23 
     | 
    
         
             
                  def for(layout, obj)
         
     | 
| 
       24 
     | 
    
         
            -
                    return ModelAdapters::Hash if !obj || %i 
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 24 
     | 
    
         
            +
                    return ModelAdapters::Hash if !obj || %i[hash hash_list].include?(layout)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    adapter = @adapters.detect { |a| a.handle?(layout, obj) }
         
     | 
| 
       26 
27 
     | 
    
         
             
                    adapter || ModelAdapters::Hash
         
     | 
| 
       27 
28 
     | 
    
         
             
                  end
         
     | 
| 
       28 
29 
     | 
    
         | 
| 
       29 
30 
     | 
    
         
             
                  # Shortcut to Input::clean.
         
     | 
| 
       30 
     | 
    
         
            -
                  def input_clean(* 
     | 
| 
       31 
     | 
    
         
            -
                    self::Input.clean(* 
     | 
| 
      
 31 
     | 
    
         
            +
                  def input_clean(*)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    self::Input.clean(*)
         
     | 
| 
       32 
33 
     | 
    
         
             
                  end
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
       34 
35 
     | 
    
         
             
                  # Shortcut to get an instance of Input model adapter.
         
     | 
| 
       35 
     | 
    
         
            -
                  def input(* 
     | 
| 
       36 
     | 
    
         
            -
                    self::Input.new(* 
     | 
| 
      
 36 
     | 
    
         
            +
                  def input(*)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    self::Input.new(*)
         
     | 
| 
       37 
38 
     | 
    
         
             
                  end
         
     | 
| 
       38 
39 
     | 
    
         | 
| 
       39 
40 
     | 
    
         
             
                  # Shortcut to get an instance of Output model adapter.
         
     | 
| 
       40 
     | 
    
         
            -
                  def output(* 
     | 
| 
       41 
     | 
    
         
            -
                    self::Output.new(* 
     | 
| 
      
 41 
     | 
    
         
            +
                  def output(*)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    self::Output.new(*)
         
     | 
| 
       42 
43 
     | 
    
         
             
                  end
         
     | 
| 
       43 
44 
     | 
    
         | 
| 
       44 
45 
     | 
    
         
             
                  # Override this method to load validators from `model`
         
     | 
| 
       45 
46 
     | 
    
         
             
                  # to `params`.
         
     | 
| 
       46 
     | 
    
         
            -
                  def load_validators(model, params)
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  def load_validators(model, params); end
         
     | 
| 
       49 
48 
     | 
    
         | 
| 
       50 
49 
     | 
    
         
             
                  # Called when mounting the API. Model adapters may use this method
         
     | 
| 
       51 
50 
     | 
    
         
             
                  # to add custom meta parameters to `action`. `direction` is one of
         
     | 
| 
         @@ -63,9 +62,7 @@ module HaveAPI 
     | 
|
| 
       63 
62 
     | 
    
         
             
                # Subclass this class in your adapter and reimplement
         
     | 
| 
       64 
63 
     | 
    
         
             
                # necessary methods.
         
     | 
| 
       65 
64 
     | 
    
         
             
                class Input
         
     | 
| 
       66 
     | 
    
         
            -
                  def self.used_by(action)
         
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                  def self.used_by(action); end
         
     | 
| 
       69 
66 
     | 
    
         | 
| 
       70 
67 
     | 
    
         
             
                  def initialize(input)
         
     | 
| 
       71 
68 
     | 
    
         
             
                    @input = input
         
     | 
| 
         @@ -83,17 +80,13 @@ module HaveAPI 
     | 
|
| 
       83 
80 
     | 
    
         
             
                  end
         
     | 
| 
       84 
81 
     | 
    
         | 
| 
       85 
82 
     | 
    
         
             
                  # Return model instance from a raw input resource parameter.
         
     | 
| 
       86 
     | 
    
         
            -
                  def self.clean(model, raw, extra)
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
                  def self.clean(model, raw, extra); end
         
     | 
| 
       89 
84 
     | 
    
         
             
                end
         
     | 
| 
       90 
85 
     | 
    
         | 
| 
       91 
86 
     | 
    
         
             
                # Subclass this class in your adapter and reimplement
         
     | 
| 
       92 
87 
     | 
    
         
             
                # necessary methods.
         
     | 
| 
       93 
88 
     | 
    
         
             
                class Output
         
     | 
| 
       94 
     | 
    
         
            -
                  def self.used_by(action)
         
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  def self.used_by(action); end
         
     | 
| 
       97 
90 
     | 
    
         | 
| 
       98 
91 
     | 
    
         
             
                  def initialize(context, obj)
         
     | 
| 
       99 
92 
     | 
    
         
             
                    @context = context
         
     | 
| 
         @@ -102,14 +95,10 @@ module HaveAPI 
     | 
|
| 
       102 
95 
     | 
    
         | 
| 
       103 
96 
     | 
    
         
             
                  # Return true if input parameters contain parameter
         
     | 
| 
       104 
97 
     | 
    
         
             
                  # with `name`.
         
     | 
| 
       105 
     | 
    
         
            -
                  def has_param?(name)
         
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
                  def has_param?(name); end
         
     | 
| 
       108 
99 
     | 
    
         | 
| 
       109 
100 
     | 
    
         
             
                  # Return a parameter in an appropriate format to be sent to a client.
         
     | 
| 
       110 
     | 
    
         
            -
                  def [](name)
         
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                  def [](name); end
         
     | 
| 
       113 
102 
     | 
    
         | 
| 
       114 
103 
     | 
    
         
             
                  def meta
         
     | 
| 
       115 
104 
     | 
    
         
             
                    {}
         
     | 
| 
         @@ -6,7 +6,7 @@ module HaveAPI::ModelAdapters 
     | 
|
| 
       6 
6 
     | 
    
         
             
                register
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                def self.handle?(layout, klass)
         
     | 
| 
       9 
     | 
    
         
            -
                  klass < ::ActiveRecord::Base && %i 
     | 
| 
      
 9 
     | 
    
         
            +
                  klass < ::ActiveRecord::Base && %i[object object_list].include?(layout)
         
     | 
| 
       10 
10 
     | 
    
         
             
                end
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                def self.load_validators(model, params)
         
     | 
| 
         @@ -34,10 +34,10 @@ module HaveAPI::ModelAdapters 
     | 
|
| 
       34 
34 
     | 
    
         
             
                      # it well, it is not necessary to fix.
         
     | 
| 
       35 
35 
     | 
    
         
             
                      args.concat(ar_default_includes).uniq
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                      if  
     | 
| 
       38 
     | 
    
         
            -
                        q.includes(*args)
         
     | 
| 
       39 
     | 
    
         
            -
                      else
         
     | 
| 
      
 37 
     | 
    
         
            +
                      if args.empty?
         
     | 
| 
       40 
38 
     | 
    
         
             
                        q
         
     | 
| 
      
 39 
     | 
    
         
            +
                      else
         
     | 
| 
      
 40 
     | 
    
         
            +
                        q.includes(*args)
         
     | 
| 
       41 
41 
     | 
    
         
             
                      end
         
     | 
| 
       42 
42 
     | 
    
         
             
                    end
         
     | 
| 
       43 
43 
     | 
    
         | 
| 
         @@ -45,6 +45,7 @@ module HaveAPI::ModelAdapters 
     | 
|
| 
       45 
45 
     | 
    
         
             
                    # in an array of symbols and hashes.
         
     | 
| 
       46 
46 
     | 
    
         
             
                    def ar_parse_includes(raw)
         
     | 
| 
       47 
47 
     | 
    
         
             
                      return @ar_parsed_includes if @ar_parsed_includes
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
       48 
49 
     | 
    
         
             
                      @ar_parsed_includes = ar_inner_includes(raw).select do |inc|
         
     | 
| 
       49 
50 
     | 
    
         
             
                        # Drop associations that are not registered in the AR:
         
     | 
| 
       50 
51 
     | 
    
         
             
                        #   The API resource may have associations that are not based on
         
     | 
| 
         @@ -70,7 +71,7 @@ module HaveAPI::ModelAdapters 
     | 
|
| 
       70 
71 
     | 
    
         
             
                        if assoc.index('__')
         
     | 
| 
       71 
72 
     | 
    
         
             
                          tmp = {}
         
     | 
| 
       72 
73 
     | 
    
         
             
                          parts = assoc.split('__')
         
     | 
| 
       73 
     | 
    
         
            -
                          tmp[parts.first.to_sym] = ar_inner_includes([parts[1 
     | 
| 
      
 74 
     | 
    
         
            +
                          tmp[parts.first.to_sym] = ar_inner_includes([parts[1..].join('__')])
         
     | 
| 
       74 
75 
     | 
    
         | 
| 
       75 
76 
     | 
    
         
             
                          args << tmp
         
     | 
| 
       76 
77 
     | 
    
         
             
                        else
         
     | 
| 
         @@ -115,39 +116,37 @@ module HaveAPI::ModelAdapters 
     | 
|
| 
       115 
116 
     | 
    
         
             
                    action.meta(:object) do
         
     | 
| 
       116 
117 
     | 
    
         
             
                      output do
         
     | 
| 
       117 
118 
     | 
    
         
             
                        custom :path_params, label: 'URL parameters',
         
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
      
 119 
     | 
    
         
            +
                                             desc: 'An array of parameters needed to resolve URL to this object'
         
     | 
| 
       119 
120 
     | 
    
         
             
                        bool :resolved, label: 'Resolved', desc: 'True if the association is resolved'
         
     | 
| 
       120 
121 
     | 
    
         
             
                      end
         
     | 
| 
       121 
122 
     | 
    
         
             
                    end
         
     | 
| 
       122 
123 
     | 
    
         | 
| 
       123 
     | 
    
         
            -
                     
     | 
| 
       124 
     | 
    
         
            -
                      clean = Proc.new do |raw|
         
     | 
| 
       125 
     | 
    
         
            -
                        if raw.is_a?(String)
         
     | 
| 
       126 
     | 
    
         
            -
                          raw.strip.split(',')
         
     | 
| 
       127 
     | 
    
         
            -
                        elsif raw.is_a?(Array)
         
     | 
| 
       128 
     | 
    
         
            -
                          raw
         
     | 
| 
       129 
     | 
    
         
            -
                        else
         
     | 
| 
       130 
     | 
    
         
            -
                          nil
         
     | 
| 
       131 
     | 
    
         
            -
                        end
         
     | 
| 
       132 
     | 
    
         
            -
                      end
         
     | 
| 
      
 124 
     | 
    
         
            +
                    return unless %i[object object_list].include?(action.input.layout)
         
     | 
| 
       133 
125 
     | 
    
         | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
            to go even deeper, use e.g. 'user,node__location__environment'.
         
     | 
| 
       140 
     | 
    
         
            -
            END
         
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
     | 
    
         
            -
                      action.meta(:global) do
         
     | 
| 
       143 
     | 
    
         
            -
                        input do
         
     | 
| 
       144 
     | 
    
         
            -
                          custom :includes, label: 'Included associations',
         
     | 
| 
       145 
     | 
    
         
            -
                                 desc: desc, &clean
         
     | 
| 
       146 
     | 
    
         
            -
                        end
         
     | 
| 
      
 126 
     | 
    
         
            +
                    clean = proc do |raw|
         
     | 
| 
      
 127 
     | 
    
         
            +
                      if raw.is_a?(String)
         
     | 
| 
      
 128 
     | 
    
         
            +
                        raw.strip.split(',')
         
     | 
| 
      
 129 
     | 
    
         
            +
                      elsif raw.is_a?(Array)
         
     | 
| 
      
 130 
     | 
    
         
            +
                        raw
         
     | 
| 
       147 
131 
     | 
    
         
             
                      end
         
     | 
| 
      
 132 
     | 
    
         
            +
                    end
         
     | 
| 
       148 
133 
     | 
    
         | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
      
 134 
     | 
    
         
            +
                    desc = <<~END
         
     | 
| 
      
 135 
     | 
    
         
            +
                      A list of names of associated resources separated by a comma.
         
     | 
| 
      
 136 
     | 
    
         
            +
                      Nested associations are declared with '__' between resource names.
         
     | 
| 
      
 137 
     | 
    
         
            +
                      For example, 'user,node' will resolve the two associations.
         
     | 
| 
      
 138 
     | 
    
         
            +
                      To resolve further associations of node, use e.g. 'user,node__location',
         
     | 
| 
      
 139 
     | 
    
         
            +
                      to go even deeper, use e.g. 'user,node__location__environment'.
         
     | 
| 
      
 140 
     | 
    
         
            +
                    END
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                    action.meta(:global) do
         
     | 
| 
      
 143 
     | 
    
         
            +
                      input do
         
     | 
| 
      
 144 
     | 
    
         
            +
                        custom :includes, label: 'Included associations',
         
     | 
| 
      
 145 
     | 
    
         
            +
                                          desc:, &clean
         
     | 
| 
      
 146 
     | 
    
         
            +
                      end
         
     | 
| 
       150 
147 
     | 
    
         
             
                    end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                    action.send(:include, Action::InstanceMethods)
         
     | 
| 
       151 
150 
     | 
    
         
             
                  end
         
     | 
| 
       152 
151 
     | 
    
         | 
| 
       153 
152 
     | 
    
         
             
                  def has_param?(name)
         
     | 
| 
         @@ -169,14 +168,14 @@ END 
     | 
|
| 
       169 
168 
     | 
    
         
             
                  def meta
         
     | 
| 
       170 
169 
     | 
    
         
             
                    res = @context.action.resource
         
     | 
| 
       171 
170 
     | 
    
         | 
| 
       172 
     | 
    
         
            -
                    if @context.action.name.demodulize == 'Index' \
         
     | 
| 
      
 171 
     | 
    
         
            +
                    params = if @context.action.name.demodulize == 'Index' \
         
     | 
| 
       173 
172 
     | 
    
         
             
                       && !@context.action.resolve \
         
     | 
| 
       174 
173 
     | 
    
         
             
                       && res.const_defined?(:Show)
         
     | 
| 
       175 
     | 
    
         
            -
             
     | 
| 
      
 174 
     | 
    
         
            +
                               res::Show.resolve_path_params(@object)
         
     | 
| 
       176 
175 
     | 
    
         | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
             
     | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
      
 176 
     | 
    
         
            +
                             else
         
     | 
| 
      
 177 
     | 
    
         
            +
                               @context.action.resolve_path_params(@object)
         
     | 
| 
      
 178 
     | 
    
         
            +
                             end
         
     | 
| 
       180 
179 
     | 
    
         | 
| 
       181 
180 
     | 
    
         
             
                    {
         
     | 
| 
       182 
181 
     | 
    
         
             
                      path_params: params.is_a?(Array) ? params : [params],
         
     | 
| 
         @@ -185,6 +184,7 @@ END 
     | 
|
| 
       185 
184 
     | 
    
         
             
                  end
         
     | 
| 
       186 
185 
     | 
    
         | 
| 
       187 
186 
     | 
    
         
             
                  protected
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
       188 
188 
     | 
    
         
             
                  # Return representation of an associated resource `param`
         
     | 
| 
       189 
189 
     | 
    
         
             
                  # with its instance in `val`.
         
     | 
| 
       190 
190 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -223,7 +223,7 @@ END 
     | 
|
| 
       223 
223 
     | 
    
         
             
                      @context.action_instance = push_ins
         
     | 
| 
       224 
224 
     | 
    
         
             
                      @context.action = push_cls
         
     | 
| 
       225 
225 
     | 
    
         | 
| 
       226 
     | 
    
         
            -
                       
     | 
| 
      
 226 
     | 
    
         
            +
                      raise "#{res_show} resolve failed" unless ret[0]
         
     | 
| 
       227 
227 
     | 
    
         | 
| 
       228 
228 
     | 
    
         
             
                      ret[1][res_show.output.namespace].update({
         
     | 
| 
       229 
229 
     | 
    
         
             
                          _meta: ret[1][:_meta].update(resolved: true)
         
     | 
| 
         @@ -234,8 +234,8 @@ END 
     | 
|
| 
       234 
234 
     | 
    
         
             
                        param.value_id => val.send(res_output[param.value_id].db_name),
         
     | 
| 
       235 
235 
     | 
    
         
             
                        param.value_label => val.send(res_output[param.value_label].db_name),
         
     | 
| 
       236 
236 
     | 
    
         
             
                        _meta: {
         
     | 
| 
       237 
     | 
    
         
            -
                          : 
     | 
| 
       238 
     | 
    
         
            -
                          : 
     | 
| 
      
 237 
     | 
    
         
            +
                          path_params: args.is_a?(Array) ? args : [args],
         
     | 
| 
      
 238 
     | 
    
         
            +
                          resolved: false
         
     | 
| 
       239 
239 
     | 
    
         
             
                        }
         
     | 
| 
       240 
240 
     | 
    
         
             
                      }
         
     | 
| 
       241 
241 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -244,49 +244,39 @@ END 
     | 
|
| 
       244 
244 
     | 
    
         
             
                  # Should an association with `name` be resolved?
         
     | 
| 
       245 
245 
     | 
    
         
             
                  def includes_include?(name)
         
     | 
| 
       246 
246 
     | 
    
         
             
                    includes = @context.action_instance.meta[:includes]
         
     | 
| 
       247 
     | 
    
         
            -
                    return unless includes
         
     | 
| 
      
 247 
     | 
    
         
            +
                    return false unless includes
         
     | 
| 
       248 
248 
     | 
    
         | 
| 
       249 
249 
     | 
    
         
             
                    name = name.to_sym
         
     | 
| 
       250 
250 
     | 
    
         | 
| 
       251 
251 
     | 
    
         
             
                    if @context.action_instance.flags[:inner_assoc]
         
     | 
| 
       252 
252 
     | 
    
         
             
                      # This action is called as an association of parent resource.
         
     | 
| 
       253 
253 
     | 
    
         
             
                      # Meta includes are already parsed and can be accessed directly.
         
     | 
| 
       254 
     | 
    
         
            -
                      includes.each do |v|
         
     | 
| 
       255 
     | 
    
         
            -
                        if v.is_a?(::Hash)
         
     | 
| 
       256 
     | 
    
         
            -
                          return true if v.has_key?(name)
         
     | 
| 
       257 
     | 
    
         
            -
                        else
         
     | 
| 
       258 
     | 
    
         
            -
                          return true if v == name
         
     | 
| 
       259 
     | 
    
         
            -
                        end
         
     | 
| 
       260 
     | 
    
         
            -
                      end
         
     | 
| 
       261 
     | 
    
         
            -
             
     | 
| 
       262 
     | 
    
         
            -
                      false
         
     | 
| 
       263 
     | 
    
         
            -
             
     | 
| 
       264 
254 
     | 
    
         
             
                    else
         
     | 
| 
       265 
255 
     | 
    
         
             
                      # This action is the one that was called by the user.
         
     | 
| 
       266 
256 
     | 
    
         
             
                      # Meta includes contains an array of strings as was sent
         
     | 
| 
       267 
257 
     | 
    
         
             
                      # by the user. The parsed includes must be fetched from
         
     | 
| 
       268 
258 
     | 
    
         
             
                      # the action itself.
         
     | 
| 
       269 
259 
     | 
    
         
             
                      includes = @context.action_instance.ar_parse_includes([])
         
     | 
| 
      
 260 
     | 
    
         
            +
                    end
         
     | 
| 
       270 
261 
     | 
    
         | 
| 
       271 
     | 
    
         
            -
             
     | 
| 
       272 
     | 
    
         
            -
             
     | 
| 
       273 
     | 
    
         
            -
             
     | 
| 
       274 
     | 
    
         
            -
             
     | 
| 
       275 
     | 
    
         
            -
             
     | 
| 
       276 
     | 
    
         
            -
                        end
         
     | 
| 
      
 262 
     | 
    
         
            +
                    includes.each do |v|
         
     | 
| 
      
 263 
     | 
    
         
            +
                      if v.is_a?(::Hash)
         
     | 
| 
      
 264 
     | 
    
         
            +
                        return true if v.has_key?(name)
         
     | 
| 
      
 265 
     | 
    
         
            +
                      elsif v == name
         
     | 
| 
      
 266 
     | 
    
         
            +
                        return true
         
     | 
| 
       277 
267 
     | 
    
         
             
                      end
         
     | 
| 
       278 
     | 
    
         
            -
             
     | 
| 
       279 
     | 
    
         
            -
                      false
         
     | 
| 
       280 
268 
     | 
    
         
             
                    end
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
                    false
         
     | 
| 
       281 
271 
     | 
    
         
             
                  end
         
     | 
| 
       282 
272 
     | 
    
         | 
| 
       283 
273 
     | 
    
         
             
                  # Create an array of includes that is passed to child association.
         
     | 
| 
       284 
274 
     | 
    
         
             
                  def includes_pass_on_to(assoc)
         
     | 
| 
       285 
275 
     | 
    
         
             
                    parsed = if @context.action_instance.flags[:inner_assoc]
         
     | 
| 
       286 
     | 
    
         
            -
             
     | 
| 
       287 
     | 
    
         
            -
             
     | 
| 
       288 
     | 
    
         
            -
             
     | 
| 
       289 
     | 
    
         
            -
             
     | 
| 
      
 276 
     | 
    
         
            +
                               @context.action_instance.meta[:includes]
         
     | 
| 
      
 277 
     | 
    
         
            +
                             else
         
     | 
| 
      
 278 
     | 
    
         
            +
                               @context.action_instance.ar_parse_includes([])
         
     | 
| 
      
 279 
     | 
    
         
            +
                             end
         
     | 
| 
       290 
280 
     | 
    
         | 
| 
       291 
281 
     | 
    
         
             
                    ret = []
         
     | 
| 
       292 
282 
     | 
    
         | 
| 
         @@ -324,7 +314,7 @@ END 
     | 
|
| 
       324 
314 
     | 
    
         | 
| 
       325 
315 
     | 
    
         
             
                  handle ::ActiveModel::Validations::ExclusionValidator do |v|
         
     | 
| 
       326 
316 
     | 
    
         
             
                    opts = {
         
     | 
| 
       327 
     | 
    
         
            -
                      values: v.options[:in] 
     | 
| 
      
 317 
     | 
    
         
            +
                      values: v.options[:in]
         
     | 
| 
       328 
318 
     | 
    
         
             
                    }
         
     | 
| 
       329 
319 
     | 
    
         
             
                    opts[:message] = v.options[:message] if v.options[:message]
         
     | 
| 
       330 
320 
     | 
    
         | 
| 
         @@ -342,7 +332,7 @@ END 
     | 
|
| 
       342 
332 
     | 
    
         | 
| 
       343 
333 
     | 
    
         
             
                  handle ::ActiveModel::Validations::InclusionValidator do |v|
         
     | 
| 
       344 
334 
     | 
    
         
             
                    opts = {
         
     | 
| 
       345 
     | 
    
         
            -
                      values: v.options[:in] 
     | 
| 
      
 335 
     | 
    
         
            +
                      values: v.options[:in]
         
     | 
| 
       346 
336 
     | 
    
         
             
                    }
         
     | 
| 
       347 
337 
     | 
    
         
             
                    opts[:message] = v.options[:message] if v.options[:message]
         
     | 
| 
       348 
338 
     | 
    
         | 
| 
         @@ -402,13 +392,13 @@ END 
     | 
|
| 
       402 
392 
     | 
    
         | 
| 
       403 
393 
     | 
    
         
             
                  def translate(v)
         
     | 
| 
       404 
394 
     | 
    
         
             
                    self.class.handlers.each do |klass, translator|
         
     | 
| 
       405 
     | 
    
         
            -
                       
     | 
| 
       406 
     | 
    
         
            -
             
     | 
| 
       407 
     | 
    
         
            -
             
     | 
| 
       408 
     | 
    
         
            -
             
     | 
| 
       409 
     | 
    
         
            -
                         
     | 
| 
       410 
     | 
    
         
            -
                        break
         
     | 
| 
      
 395 
     | 
    
         
            +
                      next unless v.is_a?(klass)
         
     | 
| 
      
 396 
     | 
    
         
            +
             
     | 
| 
      
 397 
     | 
    
         
            +
                      v.attributes.each do |attr|
         
     | 
| 
      
 398 
     | 
    
         
            +
                        @attr = attr
         
     | 
| 
      
 399 
     | 
    
         
            +
                        instance_exec(v, &translator)
         
     | 
| 
       411 
400 
     | 
    
         
             
                      end
         
     | 
| 
      
 401 
     | 
    
         
            +
                      break
         
     | 
| 
       412 
402 
     | 
    
         
             
                    end
         
     | 
| 
       413 
403 
     | 
    
         
             
                  end
         
     | 
| 
       414 
404 
     | 
    
         
             
                end
         
     | 
| 
         @@ -1,6 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module HaveAPI
         
     | 
| 
       2 
2 
     | 
    
         
             
              module OutputFormatters
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
3 
     | 
    
         
             
              end
         
     | 
| 
       5 
4 
     | 
    
         | 
| 
       6 
5 
     | 
    
         
             
              class OutputFormatter
         
     | 
| 
         @@ -29,7 +28,7 @@ module HaveAPI 
     | 
|
| 
       29 
28 
     | 
    
         
             
                    end
         
     | 
| 
       30 
29 
     | 
    
         
             
                  end
         
     | 
| 
       31 
30 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                   
     | 
| 
      
 31 
     | 
    
         
            +
                  !@formatter.nil?
         
     | 
| 
       33 
32 
     | 
    
         
             
                end
         
     | 
| 
       34 
33 
     | 
    
         | 
| 
       35 
34 
     | 
    
         
             
                def format(status, response, message = nil, errors = nil, version: true)
         
     | 
| 
         @@ -45,14 +44,15 @@ module HaveAPI 
     | 
|
| 
       45 
44 
     | 
    
         
             
                end
         
     | 
| 
       46 
45 
     | 
    
         | 
| 
       47 
46 
     | 
    
         
             
                protected
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                def header(status, response, message = nil, errors = nil, version = nil)
         
     | 
| 
       49 
49 
     | 
    
         
             
                  ret = {}
         
     | 
| 
       50 
50 
     | 
    
         
             
                  ret[:version] = HaveAPI::PROTOCOL_VERSION if version
         
     | 
| 
       51 
51 
     | 
    
         
             
                  ret.update({
         
     | 
| 
       52 
     | 
    
         
            -
                    status 
     | 
| 
       53 
     | 
    
         
            -
                    response 
     | 
| 
       54 
     | 
    
         
            -
                    message 
     | 
| 
       55 
     | 
    
         
            -
                    errors: 
     | 
| 
      
 52 
     | 
    
         
            +
                    status:,
         
     | 
| 
      
 53 
     | 
    
         
            +
                    response:,
         
     | 
| 
      
 54 
     | 
    
         
            +
                    message:,
         
     | 
| 
      
 55 
     | 
    
         
            +
                    errors:
         
     | 
| 
       56 
56 
     | 
    
         
             
                  })
         
     | 
| 
       57 
57 
     | 
    
         
             
                  ret
         
     | 
| 
       58 
58 
     | 
    
         
             
                end
         
     | 
| 
         @@ -7,7 +7,7 @@ module HaveAPI::OutputFormatters 
     | 
|
| 
       7 
7 
     | 
    
         
             
                    @types ||= []
         
     | 
| 
       8 
8 
     | 
    
         
             
                    @types += args
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                    HaveAPI::OutputFormatter.register(Kernel.const_get( 
     | 
| 
      
 10 
     | 
    
         
            +
                    HaveAPI::OutputFormatter.register(Kernel.const_get(to_s)) unless @registered
         
     | 
| 
       11 
11 
     | 
    
         
             
                    @registered = true
         
     | 
| 
       12 
12 
     | 
    
         
             
                  end
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
         @@ -22,8 +22,6 @@ module HaveAPI::OutputFormatters 
     | 
|
| 
       22 
22 
     | 
    
         
             
                  self.class.types.first
         
     | 
| 
       23 
23 
     | 
    
         
             
                end
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                def format(response)
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
                def format(response); end
         
     | 
| 
       28 
26 
     | 
    
         
             
              end
         
     | 
| 
       29 
27 
     | 
    
         
             
            end
         
     | 
| 
         @@ -4,8 +4,8 @@ module HaveAPI::Parameters 
     | 
|
| 
       4 
4 
     | 
    
         
             
                            :choices, :value_params
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
                def initialize(resource, name: nil, label: nil, desc: nil,
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
                               choices: nil, value_id: :id, value_label: :label, required: nil,
         
     | 
| 
      
 8 
     | 
    
         
            +
                               db_name: nil, fetch: nil)
         
     | 
| 
       9 
9 
     | 
    
         
             
                  @resource = resource
         
     | 
| 
       10 
10 
     | 
    
         
             
                  @resource_path = build_resource_path(resource)
         
     | 
| 
       11 
11 
     | 
    
         
             
                  @name = name || resource.resource_name.underscore.to_sym
         
     | 
| 
         @@ -17,7 +17,7 @@ module HaveAPI::Parameters 
     | 
|
| 
       17 
17 
     | 
    
         
             
                  @required = required
         
     | 
| 
       18 
18 
     | 
    
         
             
                  @db_name = db_name
         
     | 
| 
       19 
19 
     | 
    
         
             
                  @extra = {
         
     | 
| 
       20 
     | 
    
         
            -
                      fetch: 
     | 
| 
      
 20 
     | 
    
         
            +
                      fetch:
         
     | 
| 
       21 
21 
     | 
    
         
             
                  }
         
     | 
| 
       22 
22 
     | 
    
         
             
                end
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
         @@ -65,7 +65,7 @@ module HaveAPI::Parameters 
     | 
|
| 
       65 
65 
     | 
    
         
             
                    value: context.action_prepare && {
         
     | 
| 
       66 
66 
     | 
    
         
             
                      path: val_path,
         
     | 
| 
       67 
67 
     | 
    
         
             
                      method: val_method,
         
     | 
| 
       68 
     | 
    
         
            -
                      help: "#{val_path}?method=#{val_method}" 
     | 
| 
      
 68 
     | 
    
         
            +
                      help: "#{val_path}?method=#{val_method}"
         
     | 
| 
       69 
69 
     | 
    
         
             
                    },
         
     | 
| 
       70 
70 
     | 
    
         
             
                    choices: {
         
     | 
| 
       71 
71 
     | 
    
         
             
                      path: choices_path,
         
     | 
| 
         @@ -76,13 +76,13 @@ module HaveAPI::Parameters 
     | 
|
| 
       76 
76 
     | 
    
         
             
                end
         
     | 
| 
       77 
77 
     | 
    
         | 
| 
       78 
78 
     | 
    
         
             
                def validate_build_output
         
     | 
| 
       79 
     | 
    
         
            -
                  %i 
     | 
| 
      
 79 
     | 
    
         
            +
                  %i[value_id value_label].each do |name|
         
     | 
| 
       80 
80 
     | 
    
         
             
                    v = instance_variable_get("@#{name}")
         
     | 
| 
       81 
81 
     | 
    
         | 
| 
       82 
82 
     | 
    
         
             
                    [show_action, show_index].each do |klass|
         
     | 
| 
       83 
83 
     | 
    
         
             
                      next unless klass.instance_variable_get('@output')[v].nil?
         
     | 
| 
       84 
84 
     | 
    
         | 
| 
       85 
     | 
    
         
            -
                       
     | 
| 
      
 85 
     | 
    
         
            +
                      raise "association to '#{@resource}': value_label '#{v}' is not an output parameter of '#{klass}'"
         
     | 
| 
       86 
86 
     | 
    
         
             
                    end
         
     | 
| 
       87 
87 
     | 
    
         
             
                  end
         
     | 
| 
       88 
88 
     | 
    
         
             
                end
         
     | 
| 
         @@ -106,6 +106,7 @@ module HaveAPI::Parameters 
     | 
|
| 
       106 
106 
     | 
    
         
             
                end
         
     | 
| 
       107 
107 
     | 
    
         | 
| 
       108 
108 
     | 
    
         
             
                private
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
       109 
110 
     | 
    
         
             
                def build_resource_path(r)
         
     | 
| 
       110 
111 
     | 
    
         
             
                  path = []
         
     | 
| 
       111 
112 
     | 
    
         
             
                  top_module = Kernel
         
     | 
| 
         @@ -115,7 +116,6 @@ module HaveAPI::Parameters 
     | 
|
| 
       115 
116 
     | 
    
         | 
| 
       116 
117 
     | 
    
         
             
                    begin
         
     | 
| 
       117 
118 
     | 
    
         
             
                      top_module.obj_type
         
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
119 
     | 
    
         
             
                    rescue NoMethodError
         
     | 
| 
       120 
120 
     | 
    
         
             
                      next
         
     | 
| 
       121 
121 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -2,7 +2,7 @@ require 'date' 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module HaveAPI::Parameters
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Typed
         
     | 
| 
       5 
     | 
    
         
            -
                ATTRIBUTES = %i 
     | 
| 
      
 5 
     | 
    
         
            +
                ATTRIBUTES = %i[label desc type db_name default fill clean protected load_validators].freeze
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
                attr_reader :name, :label, :desc, :type, :default
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
         @@ -14,14 +14,14 @@ module HaveAPI::Parameters 
     | 
|
| 
       14 
14 
     | 
    
         
             
                  @label = myargs.delete(:label) || name.to_s.capitalize
         
     | 
| 
       15 
15 
     | 
    
         
             
                  @layout = :custom
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
                  (ATTRIBUTES - %i 
     | 
| 
      
 17 
     | 
    
         
            +
                  (ATTRIBUTES - %i[label]).each do |attr|
         
     | 
| 
       18 
18 
     | 
    
         
             
                    instance_variable_set("@#{attr}", myargs.delete(attr))
         
     | 
| 
       19 
19 
     | 
    
         
             
                  end
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
                  @type ||= String
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                  @validators = HaveAPI::ValidatorChain.new(myargs) unless myargs.empty?
         
     | 
| 
       24 
     | 
    
         
            -
                   
     | 
| 
      
 24 
     | 
    
         
            +
                  raise "unused arguments #{myargs}" unless myargs.empty?
         
     | 
| 
       25 
25 
     | 
    
         
             
                end
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                def db_name
         
     | 
| 
         @@ -52,7 +52,7 @@ module HaveAPI::Parameters 
     | 
|
| 
       52 
52 
     | 
    
         
             
                    type: @type ? @type.to_s : String.to_s,
         
     | 
| 
       53 
53 
     | 
    
         
             
                    validators: @validators ? @validators.describe : {},
         
     | 
| 
       54 
54 
     | 
    
         
             
                    default: @default,
         
     | 
| 
       55 
     | 
    
         
            -
                    protected: @protected || false 
     | 
| 
      
 55 
     | 
    
         
            +
                    protected: @protected || false
         
     | 
| 
       56 
56 
     | 
    
         
             
                  }
         
     | 
| 
       57 
57 
     | 
    
         
             
                end
         
     | 
| 
       58 
58 
     | 
    
         | 
| 
         @@ -75,7 +75,7 @@ module HaveAPI::Parameters 
     | 
|
| 
       75 
75 
     | 
    
         
             
                def clean(raw)
         
     | 
| 
       76 
76 
     | 
    
         
             
                  return instance_exec(raw, &@clean) if @clean
         
     | 
| 
       77 
77 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
                   
     | 
| 
      
 78 
     | 
    
         
            +
                  if raw.nil?
         
     | 
| 
       79 
79 
     | 
    
         
             
                    @default
         
     | 
| 
       80 
80 
     | 
    
         | 
| 
       81 
81 
     | 
    
         
             
                  elsif @type.nil?
         
     | 
| 
         @@ -93,16 +93,13 @@ module HaveAPI::Parameters 
     | 
|
| 
       93 
93 
     | 
    
         
             
                  elsif @type == ::Datetime
         
     | 
| 
       94 
94 
     | 
    
         
             
                    begin
         
     | 
| 
       95 
95 
     | 
    
         
             
                      DateTime.iso8601(raw).to_time
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
96 
     | 
    
         
             
                    rescue ArgumentError
         
     | 
| 
       98 
     | 
    
         
            -
                      raise HaveAPI::ValidationError 
     | 
| 
      
 97 
     | 
    
         
            +
                      raise HaveAPI::ValidationError, "not in ISO 8601 format '#{raw}'"
         
     | 
| 
       99 
98 
     | 
    
         
             
                    end
         
     | 
| 
       100 
99 
     | 
    
         | 
| 
       101 
100 
     | 
    
         
             
                  else
         
     | 
| 
       102 
101 
     | 
    
         
             
                    raw
         
     | 
| 
       103 
102 
     | 
    
         
             
                  end
         
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
                  val
         
     | 
| 
       106 
103 
     | 
    
         
             
                end
         
     | 
| 
       107 
104 
     | 
    
         | 
| 
       108 
105 
     | 
    
         
             
                def validate(v, params)
         
     |