ransack 0.7.0 → 0.7.1

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.
@@ -0,0 +1,60 @@
1
+ Ransack is an open source project and we encourage contributions.
2
+
3
+ ## Filing an issue
4
+
5
+ When filing an issue on the Ransack project, please provide these details:
6
+
7
+ * A comprehensive list of steps to reproduce the issue.
8
+ * The version of Ransack *and* the version of Rails.
9
+ * Any relevant stack traces ("Full trace" preferred)
10
+
11
+ In 99% of cases, this information is enough to determine the cause and solution to the problem that is being described.
12
+
13
+ Any issue that is open for 14 days without actionable information or activity will be marked as "stalled" and then closed. Stalled issues can be re-opened if the information requested is provided.
14
+
15
+ ## Pull requests
16
+
17
+ We gladly accept pull requests to fix bugs and, in some circumstances, add new features to Ransack.
18
+
19
+ Here's a quick guide:
20
+
21
+ 1. Fork the repo.
22
+
23
+ 2. Run the tests. We only take pull requests with passing tests, and it's great
24
+ to know that you have a clean slate:
25
+
26
+ $ bundle install
27
+ $ bundle exec rake test_app
28
+ $ bundle exec rake
29
+
30
+ 3. Add a test for your change. Only refactoring and documentation changes
31
+ require no new tests. If you are adding functionality or fixing a bug, we need
32
+ a test!
33
+
34
+ 4. Make the test pass.
35
+
36
+ 5. Push to your fork and submit a pull request. If the changes will apply cleanly to the latest stable branches and master branch, you will only need to submit one pull request.
37
+
38
+ At this point you're waiting on us. We like to at least comment on, if not
39
+ accept, pull requests within three business days (and, typically, one business
40
+ day). We may suggest some changes or improvements or alternatives.
41
+
42
+ Some things that will increase the chance that your pull request is accepted,
43
+ taken straight from the Ruby on Rails guide:
44
+
45
+ * Use Rails idioms and helpers
46
+ * Include tests that fail without your code, and pass with it
47
+ * Update the documentation, the surrounding one, examples elsewhere, guides,
48
+ whatever is affected by your contribution
49
+
50
+ Syntax:
51
+
52
+ * Two spaces, no tabs.
53
+ * No trailing whitespace. Blank lines should not have any space.
54
+ * Prefer &&/|| over and/or.
55
+ * `MyClass.my_method(my_arg)` not `my_method( my_arg )` or my_method my_arg.
56
+ * `a = b` and not `a=b`.
57
+ * `a_method { |block| ... }` and not `a_method { | block | ... }`
58
+ * Follow the conventions you see used in the source already.
59
+
60
+ And in case we didn't emphasize it enough: we love tests!
data/README.md CHANGED
@@ -34,7 +34,7 @@ If you're coming from MetaSearch, things to note:
34
34
 
35
35
  1. The default param key for search params is now `:q`, instead of `:search`. This is
36
36
  primarily to shorten query strings, though advanced queries (below) will still
37
- run afoul of URL length limits in most browsers and require a switch to HTTP
37
+ run afoul of URL length limits in most browsers and require a switch to HTTP
38
38
  POST requests. This key is
39
39
  [configurable](https://github.com/ernie/ransack/wiki/Configuration)
40
40
  2. `form_for` is now `search_form_for`, and validates that a Ransack::Search object
@@ -69,7 +69,7 @@ In your view:
69
69
  <% end %>
70
70
 
71
71
  `cont` (contains) and `start` (starts with) are just two of the available search predicates.
72
- See Constants for a full list.
72
+ See [Constants](https://github.com/ernie/ransack/blob/master/lib/ransack/constants.rb) for a full list and the [wiki](https://github.com/ernie/ransack/wiki/Basic-Searching) for more description.
73
73
 
74
74
  ### Advanced Mode
75
75
 
@@ -103,6 +103,56 @@ Once you've done so, you can make use of the helpers in Ransack::Helpers::FormBu
103
103
  construct much more complex search forms, such as the one on the
104
104
  [demo page](http://ransack-demo.heroku.com).
105
105
 
106
+ ### has_many and belongs_to associations
107
+
108
+ You can easily use Ransack to search in associated objects.
109
+
110
+ Given you have these associations ...
111
+
112
+ class Employee < ActiveRecord::Base
113
+ belongs_to :supervisor
114
+
115
+ # has attribute last_name:string
116
+ end
117
+
118
+ class Department < ActiveRecord::Base
119
+ has_many :supervisors
120
+
121
+ # has attribute title:string
122
+ end
123
+
124
+ class Supervisor < ActiveRecord::Base
125
+ belongs_to :department
126
+ has_many :employees
127
+
128
+ # has attribute last_name:string
129
+ end
130
+
131
+ ... and a controller ...
132
+
133
+ class SupervisorsController < ApplicationController
134
+ def index
135
+ @search = Supervisor.search(params[:q])
136
+ @supervisors = @search.result(:distinct => true)
137
+ end
138
+ end
139
+
140
+ ... you might set up your form like this ...
141
+
142
+ <%= search_form_for @search do |f| %>
143
+ <%= f.label :last_name_cont %>
144
+ <%= f.text_field :last_name_cont %>
145
+
146
+ <%= f.label :department_title_cont %>
147
+ <%= f.text_field :department_title_cont %>
148
+
149
+ <%= f.label :employees_last_name_cont %>
150
+ <%= f.text_field :employees_last_name_cont %>
151
+
152
+ <%= f.submit "search" %>
153
+ <% end %>
154
+
155
+
106
156
  ## Contributions
107
157
 
108
158
  To support the project:
@@ -0,0 +1,14 @@
1
+ module Arel
2
+
3
+ module Visitors
4
+
5
+ class DepthFirst < Visitor
6
+
7
+ unless method_defined?(:visit_Arel_Nodes_InfixOperation)
8
+ alias :visit_Arel_Nodes_InfixOperation :binary
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+ end
@@ -1,31 +1,30 @@
1
1
  require 'ransack/context'
2
2
  require 'ransack/adapters/active_record/3.1/context'
3
+ require 'ransack/adapters/active_record/compat'
3
4
  require 'polyamorous'
4
5
 
5
6
  module Ransack
6
7
  module Adapters
7
8
  module ActiveRecord
8
9
  class Context < ::Ransack::Context
9
-
10
+
10
11
  # Redefine a few things that have changed with 3.2.
11
-
12
+
12
13
  def initialize(object, options = {})
13
14
  super
14
15
  @arel_visitor = @engine.connection.visitor
15
16
  end
16
-
17
+
17
18
  def type_for(attr)
18
19
  return nil unless attr && attr.valid?
19
20
  name = attr.arel_attribute.name.to_s
20
21
  table = attr.arel_attribute.relation.table_name
21
22
 
22
- unless @engine.connection.table_exists?(table)
23
- raise "No table named #{table} exists"
24
- end
25
-
26
- @engine.connection.schema_cache.columns_hash[table][name].type
23
+ schema_cache = @engine.connection.schema_cache
24
+ raise "No table named #{table} exists" unless schema_cache.table_exists?(table)
25
+ schema_cache.columns_hash[table][name].type
27
26
  end
28
-
27
+
29
28
  def evaluate(search, opts = {})
30
29
  viz = Visitor.new
31
30
  relation = @object.where(viz.accept(search.base))
@@ -34,7 +33,7 @@ module Ransack
34
33
  end
35
34
  opts[:distinct] ? relation.uniq : relation
36
35
  end
37
-
36
+
38
37
  end
39
38
  end
40
39
  end
@@ -6,12 +6,12 @@ module Ransack
6
6
  AREL_PREDICATES = %w(eq not_eq matches does_not_match lt lteq gt gteq in not_in)
7
7
 
8
8
  DERIVED_PREDICATES = [
9
- ['cont', {:arel_predicate => 'matches', :formatter => proc {|v| "%#{v}%"}}],
10
- ['not_cont', {:arel_predicate => 'does_not_match', :formatter => proc {|v| "%#{v}%"}}],
11
- ['start', {:arel_predicate => 'matches', :formatter => proc {|v| "#{v}%"}}],
12
- ['not_start', {:arel_predicate => 'does_not_match', :formatter => proc {|v| "#{v}%"}}],
13
- ['end', {:arel_predicate => 'matches', :formatter => proc {|v| "%#{v}"}}],
14
- ['not_end', {:arel_predicate => 'does_not_match', :formatter => proc {|v| "%#{v}"}}],
9
+ ['cont', {:arel_predicate => 'matches', :formatter => proc {|v| "%#{escape_wildcards(v)}%"}}],
10
+ ['not_cont', {:arel_predicate => 'does_not_match', :formatter => proc {|v| "%#{escape_wildcards(v)}%"}}],
11
+ ['start', {:arel_predicate => 'matches', :formatter => proc {|v| "#{escape_wildcards(v)}%"}}],
12
+ ['not_start', {:arel_predicate => 'does_not_match', :formatter => proc {|v| "#{escape_wildcards(v)}%"}}],
13
+ ['end', {:arel_predicate => 'matches', :formatter => proc {|v| "%#{escape_wildcards(v)}"}}],
14
+ ['not_end', {:arel_predicate => 'does_not_match', :formatter => proc {|v| "%#{escape_wildcards(v)}"}}],
15
15
  ['true', {:arel_predicate => 'eq', :compounds => false, :type => :boolean, :validator => proc {|v| TRUE_VALUES.include?(v)}}],
16
16
  ['false', {:arel_predicate => 'eq', :compounds => false, :type => :boolean, :validator => proc {|v| TRUE_VALUES.include?(v)}, :formatter => proc {|v| !v}}],
17
17
  ['present', {:arel_predicate => 'not_eq_all', :compounds => false, :type => :boolean, :validator => proc {|v| TRUE_VALUES.include?(v)}, :formatter => proc {|v| [nil, '']}}],
@@ -19,5 +19,11 @@ module Ransack
19
19
  ['null', {:arel_predicate => 'eq', :compounds => false, :type => :boolean, :validator => proc {|v| TRUE_VALUES.include?(v)}, :formatter => proc {|v| nil}}],
20
20
  ['not_null', {:arel_predicate => 'not_eq', :compounds => false, :type => :boolean, :validator => proc {|v| TRUE_VALUES.include?(v)}, :formatter => proc {|v| nil}}]
21
21
  ]
22
+
23
+ module_function
24
+ # replace % _ \ to \% \_ \\
25
+ def escape_wildcards(unescaped)
26
+ unescaped.gsub(/\\/){ "\\\\" }.gsub(/%/, "\\%").gsub(/_/, "\\_")
27
+ end
22
28
  end
23
29
  end
@@ -13,8 +13,8 @@ module Ransack
13
13
  end
14
14
  options[:html] ||= {}
15
15
  html_options = {
16
- :class => options[:as] ? "#{options[:as]}_search" : "#{search.klass.to_s.underscore}_search",
17
- :id => options[:as] ? "#{options[:as]}_search" : "#{search.klass.to_s.underscore}_search",
16
+ :class => options[:class].present? ? "#{options[:class]}" : "#{search.klass.to_s.underscore}_search",
17
+ :id => options[:id].present? ? "#{options[:id]}" : "#{search.klass.to_s.underscore}_search",
18
18
  :method => :get
19
19
  }
20
20
  options[:as] ||= 'q'
@@ -0,0 +1,70 @@
1
+ cs:
2
+ ransack:
3
+ search: "vyhledávání"
4
+ predicate: "predikát"
5
+ and: "a"
6
+ or: "nebo"
7
+ any: "kteroukoliv"
8
+ all: "každou"
9
+ combinator: "kombinátor"
10
+ attribute: "atribut"
11
+ value: "hodnota"
12
+ condition: "podmínka"
13
+ sort: "řazení"
14
+ asc: "vzestupné"
15
+ desc: "sestupné"
16
+ predicates:
17
+ eq: "rovno"
18
+ eq_any: "rovno kterékoliv"
19
+ eq_all: "rovno všem"
20
+ not_eq: "nerovno"
21
+ not_eq_any: "nerovno kterékoliv"
22
+ not_eq_all: "nerovno všem"
23
+ matches: "odpovídá"
24
+ matches_any: "odpovídá kterékoliv"
25
+ matches_all: "odpovídá všem"
26
+ does_not_match: "neodpovídá"
27
+ does_not_match_any: "neodpovídá kterékoliv"
28
+ does_not_match_all: "neodpovídá všem"
29
+ lt: "menší než"
30
+ lt_any: "menší než kterákoliv"
31
+ lt_all: "menší než všechny"
32
+ lteq: "menší nebo rovno než"
33
+ lteq_any: "menší nebo rovno než kterákoliv"
34
+ lteq_all: "menší nebo rovno než všechny"
35
+ gt: "větší než"
36
+ gt_any: "větší než kterákoliv"
37
+ gt_all: "větší než všechny"
38
+ gteq: "větší nebo rovno než"
39
+ gteq_any: "větší nebo rovno než kterákoliv"
40
+ gteq_all: "větší nebo rovno než všechny"
41
+ in: "v"
42
+ in_any: "v kterékoliv"
43
+ in_all: "ve všech"
44
+ not_in: "není v"
45
+ not_in_any: "není v kterékoliv"
46
+ not_in_all: "není ve všech"
47
+ cont: "obsahuje"
48
+ cont_any: "obsahuje kterékoliv"
49
+ cont_all: "obsahuje všechny"
50
+ not_cont: "neobsahuje"
51
+ not_cont_any: "neobsahuje kteroukoliv"
52
+ not_cont_all: "neobsahuje všechny"
53
+ start: "začíná s"
54
+ start_any: "začíná s kteroukoliv"
55
+ start_all: "začíná se všemi"
56
+ not_start: "nezačíná s"
57
+ not_start_any: "nezačíná s kteroukoliv"
58
+ not_start_all: "nezačíná se všemi"
59
+ end: "končí s"
60
+ end_any: "končí s kteroukoliv"
61
+ end_all: "končí se všemi"
62
+ not_end: "nekončí s"
63
+ not_end_any: "nekončí s kteroukoliv"
64
+ not_end_all: "nekončí se všemi"
65
+ 'true': "je pravdivé"
66
+ 'false': "není pravdivé"
67
+ present: "je vyplněné"
68
+ blank: "je prázdné"
69
+ 'null': "je null"
70
+ not_null: "není null"
@@ -21,7 +21,7 @@ en:
21
21
  not_eq_any: "not equal to any"
22
22
  not_eq_all: "not equal to all"
23
23
  matches: "matches"
24
- matches_any: "matches_any"
24
+ matches_any: "matches any"
25
25
  matches_all: "matches all"
26
26
  does_not_match: "doesn't match"
27
27
  does_not_match_any: "doesn't match any"
@@ -0,0 +1,70 @@
1
+ es:
2
+ ransack:
3
+ search: "buscar"
4
+ predicate: "predicado"
5
+ and: "y"
6
+ or: "o"
7
+ any: "cualquier"
8
+ all: "todos"
9
+ combinator: "combinado"
10
+ attribute: "atributo"
11
+ value: "valor"
12
+ condition: "condición"
13
+ sort: "ordernar"
14
+ asc: "ascendente"
15
+ desc: "descendente"
16
+ predicates:
17
+ eq: "es igual a"
18
+ eq_any: "es igual a cualquier"
19
+ eq_all: "es igual a todos"
20
+ not_eq: "no es igual a"
21
+ not_eq_any: "no es igual a cualquier"
22
+ not_eq_all: "no es iguala todos"
23
+ matches: "coincidir"
24
+ matches_any: "coincidir a cualquier"
25
+ matches_all: "coincidir a todos"
26
+ does_not_match: "no coincide"
27
+ does_not_match_any: "no coincide con ninguna"
28
+ does_not_match_all: "no coincide con todos"
29
+ lt: "menor que"
30
+ lt_any: "menor que cualquier"
31
+ lt_all: "menor o igual a"
32
+ lteq: "less than or equal to"
33
+ lteq_any: "menor o igual a cualquier"
34
+ lteq_all: "menor o igual a todos"
35
+ gt: "mayor que"
36
+ gt_any: "mayor que cualquier"
37
+ gt_all: "mayor que todos"
38
+ gteq: "mayor que o igual a"
39
+ gteq_any: "mayor que o igual a cualquier"
40
+ gteq_all: "mayor que o igual a todos"
41
+ in: "en"
42
+ in_any: "en cualquier"
43
+ in_all: "en todos"
44
+ not_in: "no en"
45
+ not_in_any: "no en cualquier"
46
+ not_in_all: "no en todos"
47
+ cont: "contiene"
48
+ cont_any: "contiene cualquier"
49
+ cont_all: "contiene todos"
50
+ not_cont: "no contiene"
51
+ not_cont_any: "no contiene ninguna"
52
+ not_cont_all: "no contiene toda"
53
+ start: "comienza con"
54
+ start_any: "comienza con cualquier"
55
+ start_all: "comienza con toda"
56
+ not_start: "no inicia con"
57
+ not_start_any: "no comienza con cualquier"
58
+ not_start_all: "no inicia con toda"
59
+ end: "termina con"
60
+ end_any: "termina con cualquier"
61
+ end_all: "termina con todo"
62
+ not_end: "no termina con"
63
+ not_end_any: "no termina con cualquier"
64
+ not_end_all: "no termina con todo"
65
+ 'true': "es verdadero"
66
+ 'false': "es falso"
67
+ present: "es presente"
68
+ blank: "está en blanco"
69
+ 'null': "es nula"
70
+ not_null: "no es nula"
@@ -44,6 +44,10 @@ module Ransack
44
44
  false
45
45
  end
46
46
 
47
+ def inspect
48
+ "Attribute <#{name}>"
49
+ end
50
+
47
51
  end
48
52
  end
49
53
  end
@@ -200,6 +200,13 @@ module Ransack
200
200
  predicate.type || (attributes.first && attributes.first.type)
201
201
  end
202
202
 
203
+ def inspect
204
+ data =[['attributes', a.try(:map, &:name)], ['predicate', p], ['combinator', m], ['values', v.try(:map, &:value)]].reject { |e|
205
+ e[1].blank?
206
+ }.map { |v| "#{v[0]}: #{v[1]}" }.join(', ')
207
+ "Condition <#{data}>"
208
+ end
209
+
203
210
  private
204
211
 
205
212
  def valid_combinator?
@@ -154,6 +154,13 @@ module Ransack
154
154
  self
155
155
  end
156
156
 
157
+ def inspect
158
+ data =[['conditions', conditions], ['combinator', combinator]].reject { |e|
159
+ e[1].blank?
160
+ }.map { |v| "#{v[0]}: #{v[1]}" }.join(', ')
161
+ "Grouping <#{data}>"
162
+ end
163
+
157
164
  private
158
165
 
159
166
  def write_attribute(name, val)
@@ -98,6 +98,10 @@ module Ransack
98
98
  end
99
99
  end
100
100
 
101
+ def inspect
102
+ "Value <#{value}>"
103
+ end
104
+
101
105
  def array_of_arrays?(val)
102
106
  Array === val && Array === val.first
103
107
  end
@@ -72,7 +72,7 @@ module Ransack
72
72
  Nodes::Sort.new(@context).build(opts)
73
73
  end
74
74
 
75
- def respond_to?(method_id)
75
+ def respond_to?(method_id, include_private = false)
76
76
  super or begin
77
77
  method_name = method_id.to_s
78
78
  writer = method_name.sub!(/\=$/, '')
@@ -90,6 +90,10 @@ module Ransack
90
90
  end
91
91
  end
92
92
 
93
+ def inspect
94
+ "Ransack::Search<class: #{klass.name}, base: #{base.inspect}>"
95
+ end
96
+
93
97
  private
94
98
 
95
99
  def collapse_multiparameter_attributes!(attrs)
@@ -114,4 +118,4 @@ module Ransack
114
118
  end
115
119
 
116
120
  end
117
- end
121
+ end
@@ -1,3 +1,3 @@
1
1
  module Ransack
2
- VERSION = "0.7.0"
2
+ VERSION = "0.7.1"
3
3
  end
@@ -43,6 +43,11 @@ module Ransack
43
43
  s = Person.search(:doubled_name_eq => 'Aric SmithAric Smith')
44
44
  s.result.first.should eq Person.find_by_name('Aric Smith')
45
45
  end if defined?(Arel::Nodes::InfixOperation)
46
+
47
+ it "doesn't break #count if using InfixOperations" do
48
+ s = Person.search(:doubled_name_eq => 'Aric SmithAric Smith')
49
+ s.result.count.should eq 1
50
+ end if defined?(Arel::Nodes::InfixOperation)
46
51
  end
47
52
 
48
53
  describe '#ransackable_attributes' do
@@ -29,6 +29,10 @@ module Ransack
29
29
  @s.name_cont = 'ric'
30
30
  @s.result.to_sql.should match /"people"."name" LIKE '%ric%'/
31
31
  end
32
+ it 'escapes %, _ and \\ in value' do
33
+ @s.name_cont = '%_\\'
34
+ @s.result.to_sql.should match /"people"."name" LIKE '%\\%\\_\\\\%'/
35
+ end
32
36
  end
33
37
 
34
38
  describe 'not_cont' do
@@ -104,6 +104,11 @@ module Ransack
104
104
  condition.attributes.first.name.should eq 'name'
105
105
  condition.value.should eq ['Ernie', 'Bert']
106
106
  end
107
+
108
+ it 'does not evaluate the query on #inspect' do
109
+ search = Search.new(Person, :children_id_in => [1, 2, 3])
110
+ search.inspect.should_not match /ActiveRecord/
111
+ end
107
112
  end
108
113
 
109
114
  describe '#result' do
@@ -235,5 +240,11 @@ module Ransack
235
240
  end
236
241
  end
237
242
 
243
+ describe '#respond_to' do
244
+ it 'is aware of second argument' do
245
+ Search.new(Person).respond_to?(:name_eq, true).should be_true
246
+ end
247
+ end
248
+
238
249
  end
239
250
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ransack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-07-29 00:00:00.000000000 Z
13
+ date: 2012-12-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -135,6 +135,7 @@ extra_rdoc_files: []
135
135
  files:
136
136
  - .gitignore
137
137
  - .travis.yml
138
+ - CONTRIBUTING.md
138
139
  - Gemfile
139
140
  - LICENSE
140
141
  - README.md
@@ -145,6 +146,7 @@ files:
145
146
  - lib/ransack/adapters/active_record/3.0/context.rb
146
147
  - lib/ransack/adapters/active_record/3.1/context.rb
147
148
  - lib/ransack/adapters/active_record/base.rb
149
+ - lib/ransack/adapters/active_record/compat.rb
148
150
  - lib/ransack/adapters/active_record/context.rb
149
151
  - lib/ransack/configuration.rb
150
152
  - lib/ransack/constants.rb
@@ -152,7 +154,9 @@ files:
152
154
  - lib/ransack/helpers.rb
153
155
  - lib/ransack/helpers/form_builder.rb
154
156
  - lib/ransack/helpers/form_helper.rb
157
+ - lib/ransack/locale/cs.yml
155
158
  - lib/ransack/locale/en.yml
159
+ - lib/ransack/locale/es.yml
156
160
  - lib/ransack/naming.rb
157
161
  - lib/ransack/nodes.rb
158
162
  - lib/ransack/nodes/attribute.rb
@@ -200,21 +204,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
200
204
  - - ! '>='
201
205
  - !ruby/object:Gem::Version
202
206
  version: '0'
203
- segments:
204
- - 0
205
- hash: 4077471372512744125
206
207
  required_rubygems_version: !ruby/object:Gem::Requirement
207
208
  none: false
208
209
  requirements:
209
210
  - - ! '>='
210
211
  - !ruby/object:Gem::Version
211
212
  version: '0'
212
- segments:
213
- - 0
214
- hash: 4077471372512744125
215
213
  requirements: []
216
214
  rubyforge_project: ransack
217
- rubygems_version: 1.8.24
215
+ rubygems_version: 1.8.23
218
216
  signing_key:
219
217
  specification_version: 3
220
218
  summary: Object-based searching for ActiveRecord (currently).