nexter 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 74be5ca9400c99265d287af71bcaa55370a6135d
4
- data.tar.gz: 0259777790818ed8426315b0f280e1b39ab18ff4
3
+ metadata.gz: 18207b8538b39dd309f1481c2b69fc8b50261cef
4
+ data.tar.gz: ee8714526f27d7653ff607833daf07070491feb4
5
5
  SHA512:
6
- metadata.gz: d146b475e29d127b036f6b322791d354359483f1e23a8c7cb7270814f223d9a7ebb001f43e403b1130dcaf1f454d6bd5c993d95529e345085e65372d096bea70
7
- data.tar.gz: e367f99e56ed4f79bff25a3b0aad121df2c10e578c2c6604b523870c234232a3744f69ce1b0453c82ea0c9314acdabafd9a8991ecd526b125ba01de50dd4ead5
6
+ metadata.gz: 58c0c99e1ef15ebc00c9c1534c09bf68ca7dfb51d8b491c53998ac167a054d35de0a3cefb2b3bcc34925260c33bcad683701ba814a0c418c2ad72538770b4bf3
7
+ data.tar.gz: 24c2d7d37d54e2f9d62e4eed0d7766ca5e64705a4c3f61ab544def97fddeaa125f36fa884d6f6f35180cc4f8d780b93b263f4fe3a47ecd9e4b78f07cb7a23118
data/.pryrc ADDED
@@ -0,0 +1,2 @@
1
+ require "nexter"
2
+ require "../spec/book"
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Nexter
2
2
 
3
- What is Nexter ? A misspelled tv show or a killer feature ? Almost : it wraps your model with an ordered scope and cuts out the _next_ and _previous_ record. It also works with associations nested columns.
3
+ What is Nexter ? A misspelled tv show or a killer feature ? Not sure but it wraps your ActiveRecord model with an ordered scope and consistently cuts out the _next_ and _previous_ records. It also works with associations & nested columns : `order("books.genre, authors.name, published_at desc")`
4
4
 
5
5
  ## Installation
6
6
 
@@ -9,13 +9,59 @@ What is Nexter ? A misspelled tv show or a killer feature ? Almost : it wraps yo
9
9
  ## Usage
10
10
 
11
11
  ```ruby
12
- @bboks = Book.where("type" = "novel").includes(:author).order("type", "authors.name", "title")
13
- nexter = Nexter.wrap( @books.find(56), @books )
12
+ @books = Book.includes(:author).bestsellers.
13
+ order("genre", "authors.name", "published_at desc")
14
14
 
15
- nexter.next
15
+ nexter = Nexter.wrap( @books.find(56), @books )
16
16
  nexter.previous
17
+ nexter.next
17
18
  ```
18
19
 
20
+ ## Use Case Full Stack
21
+
22
+ It helps you cycle consistentely through each record of any filtered collection instead of helplessly hit the back button of your browser to find the next item of your search. It plays well with gem which keeps the state of an `ActiveRelation like [siphon](https://github.com/charly/siphon), [ransack](https://github.com/activerecord-hackery/ransack), [has_scope](https://github.com/plataformatec/has_scope) & others.
23
+
24
+ ```ruby
25
+ class Book
26
+ def nexter=(relation)
27
+ @nexter = Nexter.wrap(relation, self)
28
+ end
29
+
30
+ def next
31
+ @nexter.next || self
32
+ end
33
+
34
+ def previous
35
+ @nexter.previous || self
36
+ end
37
+ end
38
+ ```
39
+
40
+ ```ruby
41
+ class BookController
42
+ before_filter :resource, except: :index
43
+
44
+ def resource
45
+ @book_search = BookSearch.new(params[:book_search])
46
+
47
+ @book ||= Book.includes([:author]).find(params[:id]).tap do |book|
48
+ book.nexter = siphon(Book.scoped).scope(@book_search)
49
+ end
50
+ end
51
+ end
52
+ ```
53
+
54
+ ```erb
55
+ <%= link_to "previous", book_path(@book.previous, book_search: params[:book_search]) %>
56
+ <%= link_to "collection", book_path(book_search: params[:book_search]) %>
57
+ <%= link_to "next", book_path(@book.next, book_search: params[:book_search])
58
+ ```
59
+
60
+ ## TODO
61
+
62
+ - (docs) How it works
63
+ - (feature) Joins ?
64
+ - (docs) previous/next through ctrl (not preloaded)
19
65
 
20
66
  ## Contributing
21
67
 
@@ -1,3 +1,3 @@
1
1
  module Nexter
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,100 @@
1
+ module Nexter
2
+ class Wrap
3
+
4
+ attr_reader :model, :relation
5
+
6
+ # extracted values from the relation
7
+ attr_reader :order_values, :associations
8
+
9
+ # list of build strings for finale SQL
10
+ attr_reader :wheres, :reorders
11
+
12
+ DIREC = {asc: 1, desc: -1}
13
+ GOTO = {next: 1, previous: -1}
14
+
15
+ def initialize(relation, model)
16
+ @relation = relation
17
+ @model = model
18
+ @order_values = arrayize( relation.order_values )
19
+ @associations = relation.includes_values
20
+ # @cursor_column = extract_attr( @ranges.pop )
21
+ # @cursor = model.send( @cursor_column.to_sym, )
22
+ end
23
+
24
+ def next
25
+ after.first
26
+ end
27
+
28
+ def previous
29
+ before.first
30
+ end
31
+
32
+
33
+ def after
34
+ cut(:next)
35
+ relation.where( wheres.join(' OR ') )
36
+ end
37
+
38
+ def before
39
+ cut(:previous)
40
+ relation.where( wheres.join(' OR ') ).reorder( reorders.join(", ") )
41
+ end
42
+
43
+ private
44
+ # model.order(a, b,c) loop
45
+ # 1. ( (a and b and c > c.val)
46
+ # 2. (a and b > b.val)
47
+ # 3. (a > a.val))
48
+ def cut(goto = :next)
49
+ order_vals = @order_values.dup
50
+ @wheres = []
51
+ @reorders = []
52
+
53
+ while order_col = order_vals.pop do
54
+
55
+ inrange_of = order_vals.map {|col| "#{col[0]} = '#{value_of(col[0])}'"}.join(' AND ')
56
+ inrange_of = "#{inrange_of} AND" unless inrange_of.blank?
57
+
58
+ direction = order_col[1]
59
+ sign = signature(direction, goto)
60
+
61
+ bigger_than = "#{order_col[0]} #{get_bracket(sign)} '#{value_of(order_col[0])}'"
62
+
63
+ wheres << "( #{inrange_of} #{bigger_than} )"
64
+ reorders.unshift(" #{order_col[0]} #{get_direction(sign)}")
65
+ end
66
+ end
67
+
68
+ def signature(dir, goto)
69
+ sign = DIREC[dir.to_sym] * GOTO[goto]
70
+ end
71
+
72
+ def get_bracket(sign)
73
+ sign == -1 ? '<' : '>'
74
+ end
75
+
76
+ def get_direction(sign)
77
+ sign == -1 ? 'desc' : 'asc'
78
+ end
79
+
80
+ def value_of(cursor)
81
+ splits = cursor.split(".")
82
+ if splits.first == model.class.table_name || splits.size == 1
83
+ model.send(splits.last)
84
+ else
85
+ asso = model.reflections.keys.grep(/#{splits.first.singularize}/).first
86
+ model.send(asso).send(splits.last)
87
+ end
88
+ end
89
+
90
+ # helper to turn mixed order attributes to a consistant
91
+ def arrayize(array)
92
+ array.join(",").split(",").map(&:strip).map do |column|
93
+ splits = column.split(" ").map(&:strip).map(&:downcase)
94
+ splits << "asc" if splits.size == 1
95
+ splits
96
+ end
97
+ end
98
+
99
+ end
100
+ end
data/nexter.gemspec CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Nexter::VERSION
9
9
  spec.authors = ["Charles Sistovaris"]
10
10
  spec.email = ["charlysisto@gmail.com"]
11
- spec.description = %q{What is Nexter ? A misspelled tv show or a killer feature ? Almost : it wraps your model with an ordered scope and cuts out the _next_ and _previous_ record. It also works with associations nested columns.}
11
+ spec.description = %q{What is Nexter ? A misspelled tv show or a killer feature ? Almost : it wraps your model with an ordered scope and cuts out the next and previous record. It also works with associations & nested columns.}
12
12
  spec.summary = %q{Wrap your model with an ordered scope and cut out the _next_ and _previous_ record.}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/charly/nexter"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
data/spec/book.rb ADDED
@@ -0,0 +1,37 @@
1
+ Author = Struct.new(:b)
2
+
3
+ Book = Struct.new(:a, :b, :c) do
4
+
5
+ def self.table_name
6
+ "books"
7
+ end
8
+
9
+ def reflections
10
+ {:author => "blurb"}
11
+ end
12
+
13
+ def author
14
+ Author.new("nabokov")
15
+ end
16
+ end
17
+
18
+ class Relation
19
+ attr_accessor :order_values, :includes_values
20
+
21
+ def order_values
22
+ @order_values ||= ["books.a", "authors.b", "books.c"]
23
+ end
24
+
25
+ def includes_values
26
+ [:author]
27
+ end
28
+
29
+ def where(args)
30
+ self
31
+ end
32
+
33
+ def reorder(args)
34
+ self
35
+ end
36
+
37
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ describe Nexter::Wrap do
4
+
5
+ describe "#wheres" do
6
+ it "has the right SQL condition" do
7
+ relation = Relation.new.tap {|rel| rel.order_values=["authors.b", "c"]}
8
+ book = Book.new("novel", "nabokov", "ada")
9
+ nexter = Nexter::Wrap.new(relation, book)
10
+ nexter.after
11
+
12
+ expect(nexter.wheres[0]).to eq("( authors.b = 'nabokov' AND c > 'ada' )")
13
+ expect(nexter.wheres[1]).to eq("( authors.b > 'nabokov' )")
14
+ end
15
+ end
16
+
17
+
18
+ describe "#reorders" do
19
+ it "has the right SQL condition" do
20
+ relation = Relation.new.tap {|rel| rel.order_values=["authors.b", "c"]}
21
+ book = Book.new("novel", "nabokov", "ada")
22
+ nexter = Nexter::Wrap.new(relation, book)
23
+ nexter.before
24
+
25
+ expect(nexter.wheres[0]).to eq("( authors.b = 'nabokov' AND c < 'ada' )")
26
+ end
27
+
28
+ it "has the right SQL order by" do
29
+ relation = Relation.new.tap {|rel| rel.order_values=["authors.b", "c"]}
30
+ book = Book.new("novel", "nabokov", "ada")
31
+ nexter = Nexter::Wrap.new(relation, book)
32
+ nexter.before
33
+
34
+ expect(nexter.reorders[0]).to eq(" authors.b desc")
35
+ end
36
+ end
37
+
38
+
39
+
40
+ end
@@ -0,0 +1,22 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require "book"
8
+ require "nexter"
9
+ require "active_support"
10
+
11
+
12
+ RSpec.configure do |config|
13
+ config.treat_symbols_as_metadata_keys_with_true_values = true
14
+ config.run_all_when_everything_filtered = true
15
+ config.filter_run :focus
16
+
17
+ # Run specs in random order to surface order dependencies. If you find an
18
+ # order dependency and want to debug it, you can fix the order by providing
19
+ # the seed, which is printed after each run.
20
+ # --seed 1234
21
+ config.order = 'random'
22
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Sistovaris
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-20 00:00:00.000000000 Z
11
+ date: 2013-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -95,8 +95,8 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  description: 'What is Nexter ? A misspelled tv show or a killer feature ? Almost :
98
- it wraps your model with an ordered scope and cuts out the _next_ and _previous_
99
- record. It also works with associations nested columns.'
98
+ it wraps your model with an ordered scope and cuts out the next and previous record.
99
+ It also works with associations & nested columns.'
100
100
  email:
101
101
  - charlysisto@gmail.com
102
102
  executables: []
@@ -104,14 +104,21 @@ extensions: []
104
104
  extra_rdoc_files: []
105
105
  files:
106
106
  - .gitignore
107
+ - .pryrc
108
+ - .rspec
109
+ - .ruby-version
107
110
  - Gemfile
108
111
  - LICENSE.txt
109
112
  - README.md
110
113
  - Rakefile
111
114
  - lib/nexter.rb
112
115
  - lib/nexter/version.rb
116
+ - lib/nexter/wrap.rb
113
117
  - nexter.gemspec
114
- homepage: ''
118
+ - spec/book.rb
119
+ - spec/nexter/wrap_spec.rb
120
+ - spec/spec_helper.rb
121
+ homepage: https://github.com/charly/nexter
115
122
  licenses:
116
123
  - MIT
117
124
  metadata: {}
@@ -136,5 +143,8 @@ signing_key:
136
143
  specification_version: 4
137
144
  summary: Wrap your model with an ordered scope and cut out the _next_ and _previous_
138
145
  record.
139
- test_files: []
146
+ test_files:
147
+ - spec/book.rb
148
+ - spec/nexter/wrap_spec.rb
149
+ - spec/spec_helper.rb
140
150
  has_rdoc: