listings 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/README.md +66 -0
  2. data/app/assets/javascripts/listings.js +37 -6
  3. data/app/controllers/listings/listings_controller.rb +5 -2
  4. data/app/views/listings/_listing.html.haml +1 -1
  5. data/app/views/listings/_table_content.html.haml +1 -1
  6. data/app/views/listings/twitter-bootstrap-2/_side_filters.html.haml +1 -1
  7. data/app/views/listings/twitter-bootstrap-2/_top_filters.html.haml +1 -1
  8. data/app/views/listings/twitter-bootstrap-3/_side_filters.html.haml +1 -1
  9. data/app/views/listings/twitter-bootstrap-3/_top_filters.html.haml +1 -1
  10. data/lib/listings/action_view_extensions.rb +8 -2
  11. data/lib/listings/base.rb +15 -3
  12. data/lib/listings/base_field_view.rb +4 -0
  13. data/lib/listings/configuration.rb +2 -0
  14. data/lib/listings/configuration_methods.rb +7 -1
  15. data/lib/listings/custom_filter_descriptor.rb +19 -0
  16. data/lib/listings/custom_filter_view.rb +25 -0
  17. data/lib/listings/filter_descriptor.rb +4 -0
  18. data/lib/listings/filter_view.rb +8 -0
  19. data/lib/listings/kaminari_helpers_tag_patch.rb +17 -8
  20. data/lib/listings/rspec.rb +5 -0
  21. data/lib/{rspec → listings/rspec}/listings_helpers.rb +0 -0
  22. data/lib/listings/sources/active_record_data_source.rb +29 -15
  23. data/lib/listings/sources/data_source.rb +4 -0
  24. data/lib/listings/sources/object_data_source.rb +4 -0
  25. data/lib/listings/version.rb +1 -1
  26. data/lib/listings/view_helper_methods.rb +2 -0
  27. data/spec/dummy/app/listings/tracks_listing.rb +5 -0
  28. data/spec/dummy/config/initializers/listings.rb +3 -0
  29. data/spec/dummy/db/seeds.rb +4 -1
  30. data/spec/factories/tracks.rb +2 -2
  31. data/spec/factories/traits.rb +4 -0
  32. data/spec/lib/filter_parser_spec.rb +7 -1
  33. data/spec/spec_helper.rb +1 -2
  34. metadata +8 -10
  35. data/lib/rspec.rb +0 -1
data/README.md CHANGED
@@ -22,6 +22,7 @@ A listing data source have built in support for ActiveRecord and Arrays.
22
22
  * [paginates_per](#paginates_per)
23
23
  * [export](#export)
24
24
  * [css](#css)
25
+ * [Testing](#testing)
25
26
  * [i18n](#i18n)
26
27
  * [Templates](#templates)
27
28
  * [Javascript api](#javascript-api)
@@ -63,6 +64,7 @@ Create `config/initializers/listings.rb` file to make general configurations. Li
63
64
  # file: config/initializers/listings.rb
64
65
  Listings.configure do |config|
65
66
  config.theme = 'twitter-bootstrap-3' # defaults to 'twitter-bootstrap-2'
67
+ config.push_url = true # User html5 history push_state to allow back/forward navigation. defaults to false
66
68
  end
67
69
  ```
68
70
 
@@ -241,12 +243,26 @@ It supports `title:` and a block
241
243
  end
242
244
  ```
243
245
 
246
+ Also `render:` option can be used to suppress the rendering of the filter, but allowing the user to filter by it. For example to filter by the id:
247
+
248
+ ```ruby
249
+ filter :id, render: false
250
+ ```
251
+
244
252
  Filters are rendered by default by the side of the listing. With `layout` method you can change this and render them on the top.
245
253
 
246
254
  ```ruby
247
255
  layout filters: :top
248
256
  ```
249
257
 
258
+ Custom filters allows definition of custom meaning to a key. This filters are not rendered.
259
+
260
+ ```ruby
261
+ custom_filter :order_lte do |items, value|
262
+ items.where('"order" <= ?', value.to_i)
263
+ end
264
+ ```
265
+
250
266
  ### paginates_per
251
267
 
252
268
  Page size can be specified by `paginates_per`
@@ -303,6 +319,32 @@ A `column` also support a `class` option to specify a css class to be applied on
303
319
  column :title, class: 'title-style'
304
320
  ```
305
321
 
322
+ ## Testing
323
+
324
+ Include `listings/rspec` in your `spec_helper.rb`
325
+
326
+ ```ruby
327
+ # file: spec/spec_helper.rb
328
+ require 'listings/rspec'
329
+ ```
330
+
331
+ Ensure listing is able to render
332
+
333
+ ```ruby
334
+ # file: spec/listings/tracks_listing_spec.rb
335
+ require 'spec_helper'
336
+
337
+ RSpec.describe TracksListing, type: :listing do
338
+ let(:listing) { query_listing :tracks }
339
+
340
+ it 'should get tracks' do
341
+ # ... data setup ...
342
+ items = listing.items.to_a
343
+ # ... assert expected items ...
344
+ end
345
+ end
346
+ ```
347
+
306
348
  ## i18n
307
349
 
308
350
  Although titles can be specified in the listing definition, i18n support is available. Add to your locales:
@@ -336,6 +378,30 @@ use
336
378
  refreshListing('tracks')
337
379
  ```
338
380
 
381
+ Change filters
382
+
383
+ ```
384
+ $('#tracks.listings').trigger("listings:filter:key:clear", 'album_name')
385
+ $('#tracks.listings').trigger("listings:filter:key:set", ['album_name', 'Best of'])
386
+ ```
387
+
388
+ ## View Helpers
389
+
390
+ Use `render_listing` helper to include the listing by its `name`.
391
+
392
+ ```
393
+ = render_listing :tracks
394
+ ```
395
+
396
+ Use `listings_link_to_filter` helper to render a link that will set a filter. Used to example when you want the user to be able to click on a cell value to filter upon that.
397
+
398
+ ```ruby
399
+ column artist: :name do |album, value|
400
+ listings_link_to_filter(value, :artist_id, album.artist_id)
401
+ end
402
+ ```
403
+
404
+
339
405
  ## Templates
340
406
 
341
407
  There are a number of templates involved in rendering the listing. These templates can be rendered by the hosting app per listing or theme basis.
@@ -120,20 +120,17 @@ $(function(){
120
120
  $('.listing').on('click', 'a.filter, .filter a', function(e) {
121
121
  elem = $(this);
122
122
  var listingElement = elem.closest('.listing');
123
- clearSelectedItems(listingElement);
124
-
125
123
  var key = elem.data('key');
126
124
  var value = elem.data('value');
127
125
 
128
126
  var search_data = listingElement.data('search');
129
127
  if (search_data.filters[key] == value) {
130
- delete search_data.filters[key];
128
+ listingElement.trigger("listings:filter:key:clear", key)
131
129
  } else {
132
- search_data.filters[key] = value;
130
+ listingElement.trigger("listings:filter:key:set", [key, value])
133
131
  }
134
132
 
135
- listingElement.data('search', search_data);
136
- updateListingFromSearchData(listingElement);
133
+ e.preventDefault();
137
134
  }).on("listings:loaded", function(e){
138
135
  // highlight current filter
139
136
  var listingElement = $(this).closest('.listing');
@@ -145,8 +142,42 @@ $(function(){
145
142
  listingElement.find(filerLinkSelector).closest('.filter').addClass('active');
146
143
  }
147
144
 
145
+ if (listingElement.data('config').push_url && listingElement.data('skip-push-url') !== true) {
146
+ listingElement.data('skip-push-url', false);
147
+ var url = listingElement.data('url');
148
+ var queryStringStart = url.indexOf('?');
149
+ var queryString = queryStringStart == -1 ? '' : url.substring(queryStringStart);
150
+ history.pushState({listing: '#' + listingElement.attr('id')}, document.title, location.href.split('?')[0] + queryString);
151
+ }
152
+
153
+ }).on("listings:filter:key:set", function(event, key, value) {
154
+ var listingElement = $(this).closest('.listing');
155
+ clearSelectedItems(listingElement);
156
+
157
+ var search_data = listingElement.data('search');
158
+ search_data.filters[key] = value;
159
+ listingElement.data('search', search_data);
160
+
161
+ updateListingFromSearchData(listingElement);
162
+ }).on("listings:filter:key:clear", function(event, key) {
163
+ var listingElement = $(this).closest('.listing');
164
+ clearSelectedItems(listingElement);
165
+
166
+ var search_data = listingElement.data('search');
167
+ delete search_data.filters[key];
168
+ listingElement.data('search', search_data);
169
+
170
+ updateListingFromSearchData(listingElement);
148
171
  });
149
172
 
173
+ window.onpopstate = function(event) {
174
+ if (event.state && event.state.listing) {
175
+ var listing = $(event.state.listing);
176
+ listing.data('skip-push-url', true);
177
+ $.get(listing.data('url').split('?')[0] + '?' + document.location.href.split('?')[1]);
178
+ }
179
+ };
180
+
150
181
  function searchEscape(value) {
151
182
  if (value.toString().indexOf(" ") == -1) {
152
183
  return value;
@@ -16,8 +16,11 @@ module Listings
16
16
  @listing = prepare_listing params, view_context, false
17
17
 
18
18
  respond_to do |format|
19
- format.csv { send_data @listing.to_csv, filename: "#{params[:listing]}.csv" }
20
- format.xls { render 'listings/export' }
19
+ format.csv { send_data @listing.to_csv, filename: @listing.export_filename(:csv) }
20
+ format.xls do
21
+ headers["Content-Disposition"] = "attachment; filename=\"#{@listing.export_filename(:xls)}\""
22
+ render 'listings/export'
23
+ end
21
24
  end
22
25
  end
23
26
 
@@ -1,4 +1,4 @@
1
- .listing{:id => listing.name, :'data-url' => listing.url, :'data-search' => listing.search_data.to_json }
1
+ .listing{:id => listing.name, :'data-url' => listing.url, :'data-search' => listing.search_data.to_json, :'data-config' => listing.client_config.to_json }
2
2
  = listings_partial_render 'table_full', listing
3
3
 
4
4
  :javascript
@@ -34,7 +34,7 @@
34
34
  = listing.export_message
35
35
  - listing.export_formats.each do |format|
36
36
  %li
37
- = link_to format, listing.url_for_format(format)
37
+ = link_to format, listing.url_for_format(format), download: true
38
38
 
39
39
 
40
40
  - else
@@ -1,5 +1,5 @@
1
1
  .filters
2
- - listing.filters.reverse.each do |filter_view|
2
+ - listing.filters_to_render.reverse.each do |filter_view|
3
3
  %ul.nav.nav-list.well
4
4
  %li.nav-header
5
5
  = "Filter by #{filter_view.human_name}"
@@ -1,4 +1,4 @@
1
- - listing.filters.each do |filter_view|
1
+ - listing.filters_to_render.each do |filter_view|
2
2
  %li.dropdown.pull-right
3
3
  %a.dropdown-toggle(data-toggle="dropdown" href="#")
4
4
  = filter_view.human_name
@@ -1,5 +1,5 @@
1
1
  .filters.list-group
2
- - listing.filters.reverse.each do |filter_view|
2
+ - listing.filters_to_render.reverse.each do |filter_view|
3
3
  %a.list-group-item.disabled(href="#")
4
4
  = "Filter by #{filter_view.human_name}"
5
5
  - filter_view.values.each do |value|
@@ -1,4 +1,4 @@
1
- - listing.filters.each do |filter_view|
1
+ - listing.filters_to_render.each do |filter_view|
2
2
  %li.dropdown
3
3
  %a.dropdown-toggle(data-toggle="dropdown" href="#")
4
4
  = filter_view.human_name
@@ -5,7 +5,13 @@ module Listings
5
5
  options.reverse_merge! :params => {}
6
6
  params_for_listing = {:listing => key}.merge(params).merge(options[:params]).with_indifferent_access
7
7
  listing = prepare_listing(params_for_listing, self)
8
- listings_partial_render 'listing', listing
8
+ res = listings_partial_render 'listing', listing
9
+ Kaminari::Helpers::Tag.paginate_with_listings(nil)
10
+ res
11
+ end
12
+
13
+ def listings_link_to_filter(text, key, value)
14
+ link_to text, '#', onclick: "$(this).closest('.listing').trigger('listings:filter:key:set', ['#{key}', '#{escape_javascript(value)}']);return false;"
9
15
  end
10
16
 
11
17
  def listings_partial_render(view, listing, options = {})
@@ -22,7 +28,7 @@ module Listings
22
28
  params.delete :controller
23
29
  params.delete :action
24
30
 
25
- Kaminari::Helpers::Tag.listings = view_context.listings
31
+ Kaminari::Helpers::Tag.paginate_with_listings(view_context.listings)
26
32
 
27
33
  listing_class = lookup_listing_class(params[:listing])
28
34
  listing_class.new.tap do |listing|
@@ -46,7 +46,7 @@ module Listings
46
46
 
47
47
  def parse_filter(text, filter_keys)
48
48
  filters = {}
49
- filter_keys.each do |key|
49
+ filter_keys.sort_by {|k| -k.length }.each do |key|
50
50
  text = collect_filter text, key, filters
51
51
  end
52
52
 
@@ -88,12 +88,12 @@ module Listings
88
88
  end
89
89
 
90
90
  if filterable?
91
- filters.each do |filter_view|
91
+ filters_to_render.each do |filter_view|
92
92
  filter_view.values # prepare values
93
93
  end
94
94
 
95
95
  self.search_filters.each do |key, filter_value|
96
- data_source.filter(filter_with_key(key).field, filter_value)
96
+ filter_with_key(key).apply_filter(filter_value)
97
97
  end
98
98
  end
99
99
 
@@ -217,5 +217,17 @@ module Listings
217
217
  def theme
218
218
  Listings.configuration.theme
219
219
  end
220
+
221
+ def export_filename(format)
222
+ "#{kind.gsub(' ', '_')}_#{Time.now.to_s.gsub(' ', '_')}.#{format}"
223
+ end
224
+
225
+ def filters_to_render
226
+ filters.select { |f| f.render? }
227
+ end
228
+
229
+ def client_config
230
+ { push_url: Listings.configuration.push_url }
231
+ end
220
232
  end
221
233
  end
@@ -35,5 +35,9 @@ module Listings
35
35
  def is_field?
36
36
  @field_description.is_field?
37
37
  end
38
+
39
+ def descriptor
40
+ @field_description
41
+ end
38
42
  end
39
43
  end
@@ -13,9 +13,11 @@ module Listings
13
13
 
14
14
  class Configuration
15
15
  attr_accessor :theme
16
+ attr_accessor :push_url # use html5 pushState to allow back navigation of listings. default false.
16
17
 
17
18
  def initialize
18
19
  @theme = 'twitter-bootstrap-2'
20
+ @push_url = false
19
21
  end
20
22
  end
21
23
  end
@@ -5,6 +5,8 @@ require 'listings/column_descriptor'
5
5
  require 'listings/column_view'
6
6
  require 'listings/filter_descriptor'
7
7
  require 'listings/filter_view'
8
+ require 'listings/custom_filter_descriptor'
9
+ require 'listings/custom_filter_view'
8
10
 
9
11
  module Listings
10
12
  module ConfigurationMethods
@@ -57,7 +59,7 @@ module Listings
57
59
 
58
60
  def filters
59
61
  @filters ||= self.class.filters.map do |fd|
60
- FilterView.new(self, fd)
62
+ fd.build(self)
61
63
  end
62
64
  end
63
65
  end
@@ -162,6 +164,10 @@ module Listings
162
164
  filters << FilterDescriptor.new(path, props, proc)
163
165
  end
164
166
 
167
+ def custom_filter(key, &proc)
168
+ filters << CustomFilterDescriptor.new(key, proc)
169
+ end
170
+
165
171
  def layout(props = {})
166
172
  @layout_options = props
167
173
  end
@@ -0,0 +1,19 @@
1
+ module Listings
2
+ class CustomFilterDescriptor
3
+ attr_reader :key
4
+ attr_reader :proc
5
+
6
+ def initialize(key, proc)
7
+ @key = key
8
+ @proc = proc
9
+ end
10
+
11
+ def build(listing)
12
+ CustomFilterView.new(listing, self)
13
+ end
14
+
15
+ def apply_filter(value)
16
+ data_source.filter(field, value)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ module Listings
2
+ class CustomFilterView
3
+ attr_reader :listing
4
+ attr_reader :descriptor
5
+
6
+ def initialize(listing, descriptor)
7
+ @listing = listing
8
+ @descriptor = descriptor
9
+ end
10
+
11
+ def key
12
+ @descriptor.key
13
+ end
14
+
15
+ def render?
16
+ false
17
+ end
18
+
19
+ def apply_filter(value)
20
+ listing.data_source.transform_items do |items|
21
+ listing.instance_exec items, value, &@descriptor.proc
22
+ end
23
+ end
24
+ end
25
+ end
@@ -3,5 +3,9 @@ module Listings
3
3
  def initialize(path, props, proc)
4
4
  super
5
5
  end
6
+
7
+ def build(listing)
8
+ FilterView.new(listing, self)
9
+ end
6
10
  end
7
11
  end
@@ -15,5 +15,13 @@ module Listings
15
15
  value
16
16
  end
17
17
  end
18
+
19
+ def render?
20
+ @field_description.props.fetch(:render, true)
21
+ end
22
+
23
+ def apply_filter(value)
24
+ listing.data_source.filter(field, value)
25
+ end
18
26
  end
19
27
  end
@@ -1,20 +1,29 @@
1
1
  module Kaminari
2
2
  module Helpers
3
3
  class Tag
4
+ def self.paginate_with_listings(val)
5
+ Thread.current[:listings] = val
6
+ end
4
7
 
5
- def self.listings=(val)
6
- @@listings=val
8
+ def self.listings_to_paginate_with
9
+ Thread.current[:listings]
7
10
  end
8
11
 
9
12
  # patch kaminari helpers
10
13
  # passing options of mountable engine routes seems to not be working
11
- def page_url_for(page)
12
- @params.delete :page
13
- params = {@param_name => page}.merge(@params).with_indifferent_access
14
- params.delete :controller
15
- params.delete :action
16
- @@listings.listing_content_url(params)
14
+ def page_url_for_with_listing(page)
15
+ if Kaminari::Helpers::Tag.listings_to_paginate_with
16
+ @params.delete :page
17
+ params = {@param_name => page}.merge(@params).with_indifferent_access
18
+ params.delete :controller
19
+ params.delete :action
20
+ Kaminari::Helpers::Tag.listings_to_paginate_with.listing_content_url(params)
21
+ else
22
+ page_url_for_without_listing(page)
23
+ end
17
24
  end
25
+
26
+ alias_method_chain :page_url_for, :listing
18
27
  end
19
28
  end
20
29
  end
@@ -0,0 +1,5 @@
1
+ require "listings/rspec/listings_helpers"
2
+
3
+ RSpec.configure do |config|
4
+ config.include RSpec::ListingsHelpers, type: :listing
5
+ end
@@ -29,6 +29,10 @@ module Listings::Sources
29
29
  end
30
30
  end
31
31
 
32
+ def transform_items
33
+ @items = yield @items
34
+ end
35
+
32
36
  def scope
33
37
  @items = yield @items
34
38
  @items_for_filter = yield @items_for_filter
@@ -39,7 +43,7 @@ module Listings::Sources
39
43
  end
40
44
 
41
45
  def values_for_filter(field)
42
- @items_for_filter.reorder(field.query_column).pluck("distinct #{field.query_column}").reject(&:nil?)
46
+ field.all_values(@items_for_filter)
43
47
  end
44
48
 
45
49
  def search(fields, value)
@@ -62,7 +66,6 @@ module Listings::Sources
62
66
 
63
67
  def joins(relation)
64
68
  @items = @items.eager_load(relation)
65
- @items_for_filter = @items_for_filter.joins(relation)
66
69
  end
67
70
 
68
71
  def build_field(path)
@@ -89,10 +92,28 @@ module Listings::Sources
89
92
  end
90
93
  end
91
94
 
92
- class ActiveRecordField < Field
95
+ class BaseActiveRecordField < Field
93
96
  delegate :connection, to: :data_source
94
97
  delegate :quote_table_name, :quote_column_name, to: :connection
95
98
 
99
+ def initialize(data_source)
100
+ super(data_source)
101
+ end
102
+
103
+ def all_values(items)
104
+ prepare_pluck(items).reorder(query_column).pluck("distinct #{query_column}").reject(&:nil?)
105
+ end
106
+
107
+ def prepare_pluck(items)
108
+ items
109
+ end
110
+
111
+ def sort(items, direction)
112
+ items.reorder("#{query_column} #{direction}")
113
+ end
114
+ end
115
+
116
+ class ActiveRecordField < BaseActiveRecordField
96
117
  def initialize(attribute_name, data_source)
97
118
  super(data_source)
98
119
  @attribute_name = attribute_name
@@ -106,10 +127,6 @@ module Listings::Sources
106
127
  "#{quote_table_name(data_source.items.table_name)}.#{quote_column_name(@attribute_name)}"
107
128
  end
108
129
 
109
- def sort(items, direction)
110
- items.reorder("#{query_column} #{direction}")
111
- end
112
-
113
130
  def key
114
131
  @attribute_name.to_s
115
132
  end
@@ -119,10 +136,7 @@ module Listings::Sources
119
136
  end
120
137
  end
121
138
 
122
- class ActiveRecordAssociationField < Field
123
- delegate :connection, to: :data_source
124
- delegate :quote_table_name, :quote_column_name, to: :connection
125
-
139
+ class ActiveRecordAssociationField < BaseActiveRecordField
126
140
  def initialize(path, data_source)
127
141
  super(data_source)
128
142
  @path = path
@@ -130,6 +144,10 @@ module Listings::Sources
130
144
  data_source.joins(path[0])
131
145
  end
132
146
 
147
+ def prepare_pluck(items)
148
+ items.joins(@path[0])
149
+ end
150
+
133
151
  def value_for(item)
134
152
  result = item
135
153
  @path.each do |attribute_name|
@@ -144,10 +162,6 @@ module Listings::Sources
144
162
  "#{quote_table_name(association.reflection.table_name)}.#{quote_column_name(@path[1])}"
145
163
  end
146
164
 
147
- def sort(items, direction)
148
- items.reorder("#{query_column} #{direction}")
149
- end
150
-
151
165
  def key
152
166
  @path.join('_')
153
167
  end
@@ -8,6 +8,10 @@ module Listings::Sources
8
8
  def items
9
9
  end
10
10
 
11
+ # free transform items. used usually to filter the result with logic given by a block
12
+ def transform_items
13
+ end
14
+
11
15
  # applies filter to the items
12
16
  # scope will be called with a block with the ongoing items
13
17
  # the result of the block is used as the narrowed items
@@ -9,6 +9,10 @@ module Listings::Sources
9
9
  @items
10
10
  end
11
11
 
12
+ def transform_items
13
+ @items = yield @items
14
+ end
15
+
12
16
  def paginate(page, page_size)
13
17
  @items = Kaminari.paginate_array(@items).page(page).per(page_size)
14
18
  end
@@ -1,3 +1,3 @@
1
1
  module Listings
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
@@ -19,6 +19,8 @@ module Listings
19
19
  view_context.listings.listing_export_url build_params(:format => format)
20
20
  end
21
21
 
22
+ # TODO add url_for_filter that will build the search string
23
+
22
24
  def build_params(more_params)
23
25
  res = view_context.params.merge(:listing => self.name).merge(params).merge(more_params)
24
26
  res.delete param_page
@@ -6,6 +6,11 @@ class TracksListing < Listings::Base
6
6
  filter album: :id, title: 'The Album Id' do |value|
7
7
  "#{value}!"
8
8
  end
9
+ filter :order, render: false
10
+
11
+ custom_filter :order_lte do |items, value|
12
+ items.where('"order" <= ?', value.to_i)
13
+ end
9
14
 
10
15
  column :order
11
16
  column :title, searchable: true
@@ -0,0 +1,3 @@
1
+ Listings.configure do |config|
2
+ config.push_url = true
3
+ end
@@ -5,7 +5,10 @@ require 'factory_girl'
5
5
  Post.create! title: "post n-#{sn}", author: "john-#{(sn % 4) + 1}", category: "category-#{(sn % 3) + 1}"
6
6
  end
7
7
 
8
-
9
8
  (1..10).each do |sn|
10
9
  FactoryGirl.create :album
11
10
  end
11
+
12
+ (1..10).each do |sn|
13
+ FactoryGirl.create :track, album: nil
14
+ end
@@ -1,13 +1,13 @@
1
1
  FactoryGirl.define do
2
2
  factory :track do
3
3
  title
4
- order 1
4
+ order
5
5
  album nil
6
6
  end
7
7
 
8
8
  factory :object_track do
9
9
  title
10
- order 1
10
+ order
11
11
  album nil
12
12
  end
13
13
 
@@ -6,4 +6,8 @@ FactoryGirl.define do
6
6
  sequence :name do |n|
7
7
  "name #{rand(1000)} #{n}"
8
8
  end
9
+
10
+ sequence :order do |n|
11
+ rand(20)
12
+ end
9
13
  end
@@ -28,12 +28,18 @@ describe Listings do
28
28
  assert_parse_filter "album_name:'me 2' ", {album_name: "me 2"}, ""
29
29
 
30
30
  assert_parse_filter "album_name:me-1", {album_name: "me-1"}, ""
31
+
32
+ assert_parse_filter_with_keys "project_id:3", [:id, :project_id], {project_id:"3"}, ""
31
33
  end
32
34
 
33
35
  def assert_parse_filter(text, hash, left_text)
36
+ assert_parse_filter_with_keys(text, hash.keys, hash, left_text)
37
+ end
38
+
39
+ def assert_parse_filter_with_keys(text, keys, hash, left_text)
34
40
  listing = Listings::Base.new
35
41
 
36
- filters, s = listing.parse_filter text, hash.keys
42
+ filters, s = listing.parse_filter text, keys
37
43
 
38
44
  s.should eq(left_text)
39
45
  filters.should eq(hash)
@@ -4,7 +4,7 @@ require File.expand_path("../dummy/config/environment", __FILE__)
4
4
  require 'rspec/rails'
5
5
  require 'rspec/autorun'
6
6
  require 'factory_girl_rails'
7
- require File.expand_path("../../lib/rspec", __FILE__)
7
+ require File.expand_path("../../lib/listings/rspec", __FILE__)
8
8
 
9
9
  # Requires supporting ruby files with custom matchers and macros, etc,
10
10
  # in spec/support/ and its subdirectories.
@@ -42,5 +42,4 @@ RSpec.configure do |config|
42
42
  config.order = "random"
43
43
 
44
44
  config.include FactoryGirl::Syntax::Methods
45
- config.include RSpec::ListingsHelpers, type: :listing
46
45
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: listings
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-06-22 00:00:00.000000000 Z
12
+ date: 2015-06-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -210,12 +210,16 @@ files:
210
210
  - lib/listings/column_view.rb
211
211
  - lib/listings/configuration.rb
212
212
  - lib/listings/configuration_methods.rb
213
+ - lib/listings/custom_filter_descriptor.rb
214
+ - lib/listings/custom_filter_view.rb
213
215
  - lib/listings/dynamic_binding.rb
214
216
  - lib/listings/engine.rb
215
217
  - lib/listings/filter_descriptor.rb
216
218
  - lib/listings/filter_view.rb
217
219
  - lib/listings/filters/base.rb
218
220
  - lib/listings/kaminari_helpers_tag_patch.rb
221
+ - lib/listings/rspec/listings_helpers.rb
222
+ - lib/listings/rspec.rb
219
223
  - lib/listings/scope_descriptor.rb
220
224
  - lib/listings/sources/active_record_data_source.rb
221
225
  - lib/listings/sources/data_source.rb
@@ -224,8 +228,6 @@ files:
224
228
  - lib/listings/version.rb
225
229
  - lib/listings/view_helper_methods.rb
226
230
  - lib/listings.rb
227
- - lib/rspec/listings_helpers.rb
228
- - lib/rspec.rb
229
231
  - lib/tasks/listings_tasks.rake
230
232
  - LICENSE
231
233
  - Rakefile
@@ -265,6 +267,7 @@ files:
265
267
  - spec/dummy/config/environments/test.rb
266
268
  - spec/dummy/config/initializers/backtrace_silencers.rb
267
269
  - spec/dummy/config/initializers/inflections.rb
270
+ - spec/dummy/config/initializers/listings.rb
268
271
  - spec/dummy/config/initializers/mime_types.rb
269
272
  - spec/dummy/config/initializers/secret_token.rb
270
273
  - spec/dummy/config/initializers/session_store.rb
@@ -313,18 +316,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
313
316
  - - ! '>='
314
317
  - !ruby/object:Gem::Version
315
318
  version: '0'
316
- segments:
317
- - 0
318
- hash: 3767681349647885791
319
319
  required_rubygems_version: !ruby/object:Gem::Requirement
320
320
  none: false
321
321
  requirements:
322
322
  - - ! '>='
323
323
  - !ruby/object:Gem::Version
324
324
  version: '0'
325
- segments:
326
- - 0
327
- hash: 3767681349647885791
328
325
  requirements: []
329
326
  rubyforge_project:
330
327
  rubygems_version: 1.8.23.2
@@ -367,6 +364,7 @@ test_files:
367
364
  - spec/dummy/config/environments/test.rb
368
365
  - spec/dummy/config/initializers/backtrace_silencers.rb
369
366
  - spec/dummy/config/initializers/inflections.rb
367
+ - spec/dummy/config/initializers/listings.rb
370
368
  - spec/dummy/config/initializers/mime_types.rb
371
369
  - spec/dummy/config/initializers/secret_token.rb
372
370
  - spec/dummy/config/initializers/session_store.rb
@@ -1 +0,0 @@
1
- require "rspec/listings_helpers"