listings 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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"