adequate_exposure 0.0.5 → 0.0.6
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/README.md +32 -15
- data/lib/adequate_exposure/controller.rb +17 -6
- data/lib/adequate_exposure/exposure.rb +48 -12
- data/lib/adequate_exposure/version.rb +1 -1
- data/lib/adequate_exposure.rb +1 -1
- data/spec/controller_spec.rb +41 -2
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 15f771dd9996bd2a1920e2f00dbc487e568d84ce
         | 
| 4 | 
            +
              data.tar.gz: 9db2690bceba1225904077e793d780813f968774
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: e5cbf18ca89f1b543a5ef99f19059beb805991238219835d827d2090b387bfb5c8c832b10a911f287f88f4bb274ca041e3353b13d91b17e71eb544e6b12c5ee6
         | 
| 7 | 
            +
              data.tar.gz: e97dc7d95fe518d7b19a9e93ffd978240eb11de1a1ab6499777c15e6e548c36b581107eaf510e1a959929b4e4f3228da79a3b2402f84c4cef8f577b9afcef477
         | 
    
        data/README.md
    CHANGED
    
    | @@ -17,7 +17,8 @@ that down we can start talking about the API. | |
| 17 17 |  | 
| 18 18 | 
             
            ## API
         | 
| 19 19 |  | 
| 20 | 
            -
            The whole API consists of  | 
| 20 | 
            +
            The whole API consists of three methods so far: `expose`, `expose!`, and
         | 
| 21 | 
            +
            `exposure_config`.
         | 
| 21 22 |  | 
| 22 23 | 
             
            In the simplest scenario you'll just use it to expose a model in the
         | 
| 23 24 | 
             
            controller:
         | 
| @@ -33,7 +34,7 @@ ID and try to perform `Thing.find(id)`. If the ID isn't found, it'll call | |
| 33 34 | 
             
            `Thing.new(things_params)`. The result will be memoized in an `@exposed_thing`
         | 
| 34 35 | 
             
            instance variable.
         | 
| 35 36 |  | 
| 36 | 
            -
            The default resolving workflow  | 
| 37 | 
            +
            The default resolving workflow is pretty powerful and customizable. It could be
         | 
| 37 38 | 
             
            expressed with the following pseudocode:
         | 
| 38 39 |  | 
| 39 40 | 
             
            ```ruby
         | 
| @@ -108,7 +109,7 @@ Or if you (like me) absolutely hate parens in side-effect methods: | |
| 108 109 | 
             
            expose :thing, ->{ get_thing_some_way_or_another }
         | 
| 109 110 | 
             
            ```
         | 
| 110 111 |  | 
| 111 | 
            -
            There is another shortcut that allows you to redefine entire fetch block with
         | 
| 112 | 
            +
            There is another shortcut that allows you to redefine the entire fetch block with
         | 
| 112 113 | 
             
            less code:
         | 
| 113 114 |  | 
| 114 115 | 
             
            ```ruby
         | 
| @@ -120,7 +121,7 @@ expose :comments, ->{ post.comments } | |
| 120 121 | 
             
            ### `id`
         | 
| 121 122 |  | 
| 122 123 | 
             
            The default fetch logic relies on the presence of an ID. And of course Adequate
         | 
| 123 | 
            -
            Exposure allows  | 
| 124 | 
            +
            Exposure allows you to specify how exactly you want the ID to be extracted.
         | 
| 124 125 |  | 
| 125 126 | 
             
            Default behavior could be expressed using following code:
         | 
| 126 127 |  | 
| @@ -136,15 +137,17 @@ But nothing is stopping you from throwing in any arbitrary code: | |
| 136 137 | 
             
            expose :thing, id: ->{ 42 }
         | 
| 137 138 | 
             
            ```
         | 
| 138 139 |  | 
| 139 | 
            -
            Passing lambdas might not always be fun, so here are couple shortcuts that could
         | 
| 140 | 
            -
            help  | 
| 140 | 
            +
            Passing lambdas might not always be fun, so here are a couple of shortcuts that could
         | 
| 141 | 
            +
            help make life easier.
         | 
| 141 142 |  | 
| 142 143 | 
             
            ```ruby
         | 
| 143 | 
            -
            # equivalent to id: ->{ params[:custom_thing_id] }
         | 
| 144 144 | 
             
            expose :thing, id: :custom_thing_id
         | 
| 145 | 
            +
            # equivalent to
         | 
| 146 | 
            +
            expose :thing, id: ->{ params[:custom_thing_id] }
         | 
| 145 147 |  | 
| 146 | 
            -
            # equivalent to id: ->{ params[:try_this_id] || params[:or_maybe_that_id] }
         | 
| 147 148 | 
             
            expose :thing, id: [:try_this_id, :or_maybe_that_id]
         | 
| 149 | 
            +
            # equivalent to
         | 
| 150 | 
            +
            expose :thing, id: ->{ params[:try_this_id] || params[:or_maybe_that_id] }
         | 
| 148 151 | 
             
            ```
         | 
| 149 152 |  | 
| 150 153 | 
             
            ### `find`
         | 
| @@ -160,7 +163,7 @@ Where `scope` is a model scope, like `Thing` or `User.active` or | |
| 160 163 | 
             
            `Post.published`.
         | 
| 161 164 |  | 
| 162 165 | 
             
            Now, if you're using FriendlyId or Stringex or something similar, you'd have to
         | 
| 163 | 
            -
            customize your finding logic.  | 
| 166 | 
            +
            customize your finding logic. Your code might look somewhat like this:
         | 
| 164 167 |  | 
| 165 168 | 
             
            ```ruby
         | 
| 166 169 | 
             
            expose :thing, find: ->(id, scope){ scope.find_by!(slug: id) }
         | 
| @@ -184,10 +187,10 @@ expose :thing, build: ->(thing_params, scope){ scope.new(thing_params) } | |
| 184 187 |  | 
| 185 188 | 
             
            ### `build_params`
         | 
| 186 189 |  | 
| 187 | 
            -
             | 
| 190 | 
            +
            These options are responsible for calulating params before passing them to the
         | 
| 188 191 | 
             
            build step. The default behavior was modeled with Strong Parameters in mind and
         | 
| 189 | 
            -
            is somewhat smart: it calls `thing_params` controller method if it's available
         | 
| 190 | 
            -
            and request method it not `GET`. In all other cases it produces an empty hash.
         | 
| 192 | 
            +
            is somewhat smart: it calls the `thing_params` controller method if it's available
         | 
| 193 | 
            +
            and the request method it not `GET`. In all other cases it produces an empty hash.
         | 
| 191 194 |  | 
| 192 195 | 
             
            You can easily specify which controller method you want it to call instead of
         | 
| 193 196 | 
             
            `thing_params`, or just provide your own logic:
         | 
| @@ -217,7 +220,7 @@ Like before, shortcuts are there to make you happier: | |
| 217 220 |  | 
| 218 221 | 
             
            ```ruby
         | 
| 219 222 | 
             
            expose :post, scope: :published
         | 
| 220 | 
            -
            #  | 
| 223 | 
            +
            # equivalent to
         | 
| 221 224 | 
             
            expose :post, scope: ->{ Post.published }
         | 
| 222 225 | 
             
            ```
         | 
| 223 226 |  | 
| @@ -225,13 +228,13 @@ and | |
| 225 228 |  | 
| 226 229 | 
             
            ```ruby
         | 
| 227 230 | 
             
            expose :thing, parent: :current_user
         | 
| 228 | 
            -
            #  | 
| 231 | 
            +
            # equivalent to:
         | 
| 229 232 | 
             
            expose :thing, scope: ->{ current_user.things }
         | 
| 230 233 | 
             
            ```
         | 
| 231 234 |  | 
| 232 235 | 
             
            ### `model`
         | 
| 233 236 |  | 
| 234 | 
            -
            Allows to specify the model class to use. Pretty straightforward.
         | 
| 237 | 
            +
            Allows you to specify the model class to use. Pretty straightforward.
         | 
| 235 238 |  | 
| 236 239 | 
             
            ```ruby
         | 
| 237 240 | 
             
            expose :thing, model: ->{ AnotherThing }
         | 
| @@ -250,6 +253,20 @@ that: | |
| 250 253 | 
             
            expose :thing, decorate: ->(thing){ ThingDecorator.new(thing) }
         | 
| 251 254 | 
             
            ```
         | 
| 252 255 |  | 
| 256 | 
            +
            ## `exposure_config`
         | 
| 257 | 
            +
             | 
| 258 | 
            +
            You can pre-save some configuration using `exposure_config` method reuse it
         | 
| 259 | 
            +
            later.
         | 
| 260 | 
            +
             | 
| 261 | 
            +
            ```ruby
         | 
| 262 | 
            +
            exposure_config :cool_find, find: ->{ very_cool_find_code }
         | 
| 263 | 
            +
            exposure_config :cool_build, build: ->{ very_cool_build_code }
         | 
| 264 | 
            +
             | 
| 265 | 
            +
            expose :thing, with: [:cool_find, :cool_build]
         | 
| 266 | 
            +
            expose :another_thing, with: :cool_build
         | 
| 267 | 
            +
            ```
         | 
| 268 | 
            +
             | 
| 269 | 
            +
             | 
| 253 270 | 
             
            ## Contributing
         | 
| 254 271 |  | 
| 255 272 | 
             
            1. Fork it (https://github.com/rwz/adequate_exposure/fork)
         | 
| @@ -1,12 +1,23 @@ | |
| 1 1 | 
             
            module AdequateExposure
         | 
| 2 2 | 
             
              module Controller
         | 
| 3 | 
            -
                 | 
| 4 | 
            -
             | 
| 5 | 
            -
                 | 
| 3 | 
            +
                extend ActiveSupport::Concern
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                included{ class_attribute :exposure_configuration }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                module ClassMethods
         | 
| 8 | 
            +
                  def expose(*args, &block)
         | 
| 9 | 
            +
                    Exposure.expose! self, *args, &block
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def expose!(name, *args, &block)
         | 
| 13 | 
            +
                    expose name, *args, &block
         | 
| 14 | 
            +
                    before_action name
         | 
| 15 | 
            +
                  end
         | 
| 6 16 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 17 | 
            +
                  def exposure_config(name, options)
         | 
| 18 | 
            +
                    store = self.exposure_configuration ||= {}
         | 
| 19 | 
            +
                    self.exposure_configuration = store.merge(name => options)
         | 
| 20 | 
            +
                  end
         | 
| 10 21 | 
             
                end
         | 
| 11 22 | 
             
              end
         | 
| 12 23 | 
             
            end
         | 
| @@ -41,12 +41,51 @@ module AdequateExposure | |
| 41 41 | 
             
                end
         | 
| 42 42 |  | 
| 43 43 | 
             
                def normalize_options
         | 
| 44 | 
            +
                  normalize_with_option
         | 
| 45 | 
            +
                  normalize_id_option
         | 
| 46 | 
            +
                  normalize_model_option
         | 
| 47 | 
            +
                  normalize_build_params_option
         | 
| 48 | 
            +
                  normalize_scope_options
         | 
| 49 | 
            +
                  normalize_parent_option
         | 
| 50 | 
            +
                  normalize_from_option
         | 
| 51 | 
            +
                  normalize_find_by_option
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def normalize_find_by_option
         | 
| 55 | 
            +
                  if find_by = options.delete(:find_by)
         | 
| 56 | 
            +
                    merge_lambda_option :find, ->(id, scope){ scope.find_by!(find_by => id) }
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def normalize_parent_option
         | 
| 61 | 
            +
                  exposure_name = options.fetch(:name)
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  if parent = options.delete(:parent)
         | 
| 64 | 
            +
                    merge_lambda_option :scope, ->{ send(parent).send(exposure_name.to_s.pluralize) }
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def normalize_from_option
         | 
| 44 69 | 
             
                  exposure_name = options.fetch(:name)
         | 
| 45 70 |  | 
| 71 | 
            +
                  if from = options.delete(:from)
         | 
| 72 | 
            +
                    merge_lambda_option :fetch, ->{ send(from).send(exposure_name) }
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                def normalize_with_option
         | 
| 77 | 
            +
                  if configs = options.delete(:with)
         | 
| 78 | 
            +
                    Array.wrap(configs).each{ |config| reverse_merge_config! config }
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def normalize_id_option
         | 
| 46 83 | 
             
                  normalize_non_proc_option :id do |ids|
         | 
| 47 84 | 
             
                    ->{ Array.wrap(ids).map{ |id| params[id] }.find(&:present?) }
         | 
| 48 85 | 
             
                  end
         | 
| 86 | 
            +
                end
         | 
| 49 87 |  | 
| 88 | 
            +
                def normalize_model_option
         | 
| 50 89 | 
             
                  normalize_non_proc_option :model do |value|
         | 
| 51 90 | 
             
                    model = if [String, Symbol].include?(value.class)
         | 
| 52 91 | 
             
                      value.to_s.classify.constantize
         | 
| @@ -56,27 +95,19 @@ module AdequateExposure | |
| 56 95 |  | 
| 57 96 | 
             
                    ->{ model }
         | 
| 58 97 | 
             
                  end
         | 
| 98 | 
            +
                end
         | 
| 59 99 |  | 
| 100 | 
            +
                def normalize_build_params_option
         | 
| 60 101 | 
             
                  normalize_non_proc_option :build_params do |value|
         | 
| 61 102 | 
             
                    options[:build_params_method] = value
         | 
| 62 103 | 
             
                    nil
         | 
| 63 104 | 
             
                  end
         | 
| 105 | 
            +
                end
         | 
| 64 106 |  | 
| 107 | 
            +
                def normalize_scope_options
         | 
| 65 108 | 
             
                  normalize_non_proc_option :scope do |custom_scope|
         | 
| 66 109 | 
             
                    ->(model){ model.send(custom_scope) }
         | 
| 67 110 | 
             
                  end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                  if parent = options.delete(:parent)
         | 
| 70 | 
            -
                    merge_lambda_option :scope, ->{ send(parent).send(exposure_name.to_s.pluralize) }
         | 
| 71 | 
            -
                  end
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                  if from = options.delete(:from)
         | 
| 74 | 
            -
                    merge_lambda_option :fetch, ->{ send(from).send(exposure_name) }
         | 
| 75 | 
            -
                  end
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                  if find_by = options.delete(:find_by)
         | 
| 78 | 
            -
                    merge_lambda_option :find, ->(id, scope){ scope.find_by!(find_by => id) }
         | 
| 79 | 
            -
                  end
         | 
| 80 111 | 
             
                end
         | 
| 81 112 |  | 
| 82 113 | 
             
                def normalize_non_proc_option(name)
         | 
| @@ -127,5 +158,10 @@ module AdequateExposure | |
| 127 158 | 
             
                    fail ArgumentError, "Using #{name.inspect} option with other options doesn't make sense"
         | 
| 128 159 | 
             
                  end
         | 
| 129 160 | 
             
                end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                def reverse_merge_config!(name)
         | 
| 163 | 
            +
                  config = controller.exposure_configuration.fetch(name)
         | 
| 164 | 
            +
                  options.reverse_merge! config
         | 
| 165 | 
            +
                end
         | 
| 130 166 | 
             
              end
         | 
| 131 167 | 
             
            end
         | 
    
        data/lib/adequate_exposure.rb
    CHANGED
    
    
    
        data/spec/controller_spec.rb
    CHANGED
    
    | @@ -14,7 +14,7 @@ describe AdequateExposure::Controller do | |
| 14 14 |  | 
| 15 15 | 
             
              let(:controller_klass) do
         | 
| 16 16 | 
             
                Class.new(BaseController) do
         | 
| 17 | 
            -
                   | 
| 17 | 
            +
                  include AdequateExposure::Controller
         | 
| 18 18 | 
             
                end
         | 
| 19 19 | 
             
              end
         | 
| 20 20 |  | 
| @@ -22,7 +22,7 @@ describe AdequateExposure::Controller do | |
| 22 22 | 
             
              let(:controller){ controller_klass.new }
         | 
| 23 23 | 
             
              before{ allow(controller).to receive(:request){ request } }
         | 
| 24 24 |  | 
| 25 | 
            -
              %w[expose expose!].each do |method_name|
         | 
| 25 | 
            +
              %w[expose expose! exposure_config].each do |method_name|
         | 
| 26 26 | 
             
                define_method method_name do |*args, &block|
         | 
| 27 27 | 
             
                  controller_klass.send method_name, *args, &block
         | 
| 28 28 | 
             
                end
         | 
| @@ -54,6 +54,45 @@ describe AdequateExposure::Controller do | |
| 54 54 | 
             
                end
         | 
| 55 55 | 
             
              end
         | 
| 56 56 |  | 
| 57 | 
            +
              context ".exposure_config" do
         | 
| 58 | 
            +
                it "subclass configration doesn't propagate to superclass" do
         | 
| 59 | 
            +
                  controller_subklass = Class.new(controller_klass)
         | 
| 60 | 
            +
                  controller_klass.exposure_config :foo, :bar
         | 
| 61 | 
            +
                  controller_subklass.exposure_config :foo, :lol
         | 
| 62 | 
            +
                  controller_subklass.exposure_config :fizz, :buzz
         | 
| 63 | 
            +
                  expect(controller_subklass.exposure_configuration).to eq(foo: :lol, fizz: :buzz)
         | 
| 64 | 
            +
                  expect(controller_klass.exposure_configuration).to eq(foo: :bar)
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                context "applying" do
         | 
| 68 | 
            +
                  let(:thing){ double("Thing") }
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  before do
         | 
| 71 | 
            +
                    exposure_config :sluggable, find_by: :slug
         | 
| 72 | 
            +
                    exposure_config :weird_id_name, id: :check_this_out
         | 
| 73 | 
            +
                    exposure_config :another_id_name, id: :whee
         | 
| 74 | 
            +
                    controller.params.merge! check_this_out: "foo", whee: "wut"
         | 
| 75 | 
            +
                  end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  after{ expect(controller.thing).to eq(thing) }
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  it "can be reused later" do
         | 
| 80 | 
            +
                    expose :thing, with: :weird_id_name
         | 
| 81 | 
            +
                    expect(Thing).to receive(:find).with("foo").and_return(thing)
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  it "can apply multple configs at once" do
         | 
| 85 | 
            +
                    expose :thing, with: [:weird_id_name, :sluggable]
         | 
| 86 | 
            +
                    expect(Thing).to receive(:find_by!).with(slug: "foo").and_return(thing)
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  it "applies multiple configs in a correct order" do
         | 
| 90 | 
            +
                    expose :thing, with: [:another_id_name, :weird_id_name]
         | 
| 91 | 
            +
                    expect(Thing).to receive(:find).with("wut").and_return(thing)
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
             | 
| 57 96 | 
             
              context "with block" do
         | 
| 58 97 | 
             
                before{ expose(:thing){ compute_thing } }
         | 
| 59 98 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: adequate_exposure
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.6
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Pavel Pravosud
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2014-07- | 
| 11 | 
            +
            date: 2014-07-10 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: railties
         |