ransack 2.1.0 → 2.4.0

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +32 -22
  4. data/CHANGELOG.md +60 -1
  5. data/CONTRIBUTING.md +11 -6
  6. data/Gemfile +21 -17
  7. data/README.md +56 -29
  8. data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_association.rb +2 -9
  9. data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_dependency.rb +25 -3
  10. data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +11 -0
  11. data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +1 -0
  12. data/lib/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +80 -0
  13. data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +1 -0
  14. data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +74 -0
  15. data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +93 -0
  16. data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +1 -0
  17. data/lib/{polyamorous.rb → polyamorous/polyamorous.rb} +3 -3
  18. data/lib/ransack.rb +2 -2
  19. data/lib/ransack/adapters/active_record/base.rb +1 -0
  20. data/lib/ransack/adapters/active_record/context.rb +60 -68
  21. data/lib/ransack/adapters/active_record/ransack/constants.rb +17 -2
  22. data/lib/ransack/adapters/active_record/ransack/context.rb +2 -6
  23. data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +12 -5
  24. data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -1
  25. data/lib/ransack/constants.rb +2 -3
  26. data/lib/ransack/context.rb +19 -18
  27. data/lib/ransack/helpers/form_builder.rb +5 -11
  28. data/lib/ransack/helpers/form_helper.rb +1 -1
  29. data/lib/ransack/locale/ar.yml +70 -0
  30. data/lib/ransack/locale/az.yml +1 -1
  31. data/lib/ransack/locale/ca.yml +70 -0
  32. data/lib/ransack/locale/es.yml +22 -22
  33. data/lib/ransack/locale/fa.yml +70 -0
  34. data/lib/ransack/locale/fi.yml +71 -0
  35. data/lib/ransack/locale/sk.yml +70 -0
  36. data/lib/ransack/locale/zh-CN.yml +12 -12
  37. data/lib/ransack/nodes/condition.rb +8 -0
  38. data/lib/ransack/nodes/grouping.rb +1 -1
  39. data/lib/ransack/predicate.rb +2 -1
  40. data/lib/ransack/search.rb +1 -0
  41. data/lib/ransack/translate.rb +115 -115
  42. data/lib/ransack/version.rb +1 -1
  43. data/ransack.gemspec +5 -21
  44. data/spec/helpers/polyamorous_helper.rb +3 -8
  45. data/spec/{ransack → polyamorous}/join_association_spec.rb +7 -0
  46. data/spec/{ransack → polyamorous}/join_dependency_spec.rb +18 -7
  47. data/spec/{ransack → polyamorous}/join_spec.rb +0 -0
  48. data/spec/ransack/adapters/active_record/base_spec.rb +8 -8
  49. data/spec/ransack/adapters/active_record/context_spec.rb +60 -17
  50. data/spec/ransack/helpers/form_helper_spec.rb +51 -51
  51. data/spec/ransack/predicate_spec.rb +54 -2
  52. data/spec/ransack/search_spec.rb +78 -13
  53. data/spec/spec_helper.rb +4 -0
  54. data/spec/support/schema.rb +13 -2
  55. metadata +29 -136
  56. data/lib/polyamorous/activerecord_5.0_ruby_2/join_association.rb +0 -2
  57. data/lib/polyamorous/activerecord_5.0_ruby_2/join_dependency.rb +0 -2
  58. data/lib/polyamorous/activerecord_5.1_ruby_2/join_association.rb +0 -32
  59. data/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +0 -112
  60. data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_association.rb +0 -32
  61. data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_dependency.rb +0 -113
@@ -13,6 +13,18 @@ module Ransack
13
13
  formatter: proc { |v| "%#{escape_wildcards(v)}%" }
14
14
  }
15
15
  ],
16
+ ['i_cont'.freeze, {
17
+ arel_predicate: 'matches'.freeze,
18
+ formatter: proc { |v| "%#{escape_wildcards(v.downcase)}%" },
19
+ case_insensitive: true
20
+ }
21
+ ],
22
+ ['not_i_cont'.freeze, {
23
+ arel_predicate: 'does_not_match'.freeze,
24
+ formatter: proc { |v| "%#{escape_wildcards(v.downcase)}%" },
25
+ case_insensitive: true
26
+ }
27
+ ],
16
28
  ['start'.freeze, {
17
29
  arel_predicate: 'matches'.freeze,
18
30
  formatter: proc { |v| "#{escape_wildcards(v)}%" }
@@ -102,8 +114,11 @@ module Ransack
102
114
  # replace % \ to \% \\
103
115
  def escape_wildcards(unescaped)
104
116
  case ActiveRecord::Base.connection.adapter_name
105
- when "Mysql2".freeze, "PostgreSQL".freeze
106
- # Necessary for PostgreSQL and MySQL
117
+ when "Mysql2".freeze
118
+ # Necessary for MySQL
119
+ unescaped.to_s.gsub(/([\\%_])/, '\\\\\\1')
120
+ when "PostgreSQL".freeze
121
+ # Necessary for PostgreSQL
107
122
  unescaped.to_s.gsub(/([\\%_.])/, '\\\\\\1')
108
123
  else
109
124
  unescaped
@@ -28,14 +28,10 @@ module Ransack
28
28
  @join_type = options[:join_type] || Polyamorous::OuterJoin
29
29
  @search_key = options[:search_key] || Ransack.options[:search_key]
30
30
  @associations_pot = {}
31
+ @tables_pot = {}
31
32
  @lock_associations = []
32
33
 
33
- if ::ActiveRecord::VERSION::STRING >= Constants::RAILS_5_2
34
- @base = @join_dependency.instance_variable_get(:@join_root)
35
- else
36
- @base = @join_dependency.join_root
37
- @engine = @base.base_klass.arel_engine
38
- end
34
+ @base = @join_dependency.instance_variable_get(:@join_root)
39
35
  end
40
36
 
41
37
  def bind_pair_for(key)
@@ -30,7 +30,7 @@ module Ransack
30
30
  def format_predicate(attribute)
31
31
  arel_pred = arel_predicate_for_attribute(attribute)
32
32
  arel_values = formatted_values_for_attribute(attribute)
33
- predicate = attribute.attr.public_send(arel_pred, arel_values)
33
+ predicate = attr_value_for_attribute(attribute).public_send(arel_pred, arel_values)
34
34
 
35
35
  if in_predicate?(predicate)
36
36
  predicate.right = predicate.right.map do |pr|
@@ -43,16 +43,23 @@ module Ransack
43
43
 
44
44
  def in_predicate?(predicate)
45
45
  return unless defined?(Arel::Nodes::Casted)
46
- predicate.class == Arel::Nodes::In
46
+ predicate.class == Arel::Nodes::In || predicate.class == Arel::Nodes::NotIn
47
47
  end
48
48
 
49
49
  def casted_array?(predicate)
50
- predicate.respond_to?(:val) && predicate.val.is_a?(Array)
50
+ (predicate.respond_to?(:value) && predicate.value.is_a?(Array)) || # Rails 6.1
51
+ (predicate.respond_to?(:val) && predicate.val.is_a?(Array)) # Rails 5.2, 6.0
51
52
  end
52
53
 
53
54
  def format_values_for(predicate)
54
- predicate.val.map do |value|
55
- value.is_a?(String) ? Arel::Nodes.build_quoted(value) : value
55
+ value = if predicate.respond_to?(:value)
56
+ predicate.value # Rails 6.1
57
+ else
58
+ predicate.val # Rails 5.2, 6.0
59
+ end
60
+
61
+ value.map do |val|
62
+ val.is_a?(String) ? Arel::Nodes.build_quoted(val) : val
56
63
  end
57
64
  end
58
65
 
@@ -2,7 +2,7 @@ module Ransack
2
2
  module Translate
3
3
 
4
4
  def self.i18n_key(klass)
5
- klass.model_name.i18n_key.to_s.freeze
5
+ klass.model_name.i18n_key
6
6
  end
7
7
  end
8
8
  end
@@ -45,9 +45,8 @@ module Ransack
45
45
  NOT_EQ_ALL = 'not_eq_all'.freeze
46
46
  CONT = 'cont'.freeze
47
47
 
48
- RAILS_5_1 = '5.1'.freeze
49
- RAILS_5_2 = '5.2'.freeze
50
- RAILS_5_2_0 = '5.2.0'.freeze
48
+ RAILS_6_0 = '6.0.0'.freeze
49
+ RAILS_6_1_ALPHA = '6.1.0.alpha'.freeze
51
50
 
52
51
  RANSACK_SLASH_SEARCHES = 'ransack/searches'.freeze
53
52
  RANSACK_SLASH_SEARCHES_SLASH_SEARCH = 'ransack/searches/search'.freeze
@@ -64,26 +64,28 @@ module Ransack
64
64
 
65
65
  def traverse(str, base = @base)
66
66
  str ||= ''.freeze
67
-
68
- if (segments = str.split(Constants::UNDERSCORE)).size > 0
67
+ segments = str.split(Constants::UNDERSCORE)
68
+ unless segments.empty?
69
69
  remainder = []
70
70
  found_assoc = nil
71
- while !found_assoc && segments.size > 0 do
71
+ until found_assoc || segments.empty?
72
72
  # Strip the _of_Model_type text from the association name, but hold
73
73
  # onto it in klass, for use as the next base
74
74
  assoc, klass = unpolymorphize_association(
75
75
  segments.join(Constants::UNDERSCORE)
76
- )
76
+ )
77
77
  if found_assoc = get_association(assoc, base)
78
78
  base = traverse(
79
79
  remainder.join(Constants::UNDERSCORE), klass || found_assoc.klass
80
- )
80
+ )
81
81
  end
82
82
 
83
83
  remainder.unshift segments.pop
84
84
  end
85
- raise UntraversableAssociationError,
86
- "No association matches #{str}" unless found_assoc
85
+ unless found_assoc
86
+ raise(UntraversableAssociationError,
87
+ "No association matches #{str}")
88
+ end
87
89
  end
88
90
 
89
91
  klassify(base)
@@ -95,18 +97,17 @@ module Ransack
95
97
  path = []
96
98
  segments = str.split(Constants::UNDERSCORE)
97
99
  association_parts = []
98
- if (segments = str.split(Constants::UNDERSCORE)).size > 0
99
- while segments.size > 0 &&
100
- !base.columns_hash[segments.join(Constants::UNDERSCORE)] &&
101
- association_parts << segments.shift do
100
+ unless segments.empty?
101
+ while !segments.empty? &&
102
+ !base.columns_hash[segments.join(Constants::UNDERSCORE)] &&
103
+ association_parts << segments.shift
102
104
  assoc, klass = unpolymorphize_association(
103
105
  association_parts.join(Constants::UNDERSCORE)
104
- )
105
- if found_assoc = get_association(assoc, base)
106
- path += association_parts
107
- association_parts = []
108
- base = klassify(klass || found_assoc)
109
- end
106
+ )
107
+ next unless found_assoc = get_association(assoc, base)
108
+ path += association_parts
109
+ association_parts = []
110
+ base = klassify(klass || found_assoc)
110
111
  end
111
112
  end
112
113
 
@@ -127,7 +128,7 @@ module Ransack
127
128
 
128
129
  def ransackable_attribute?(str, klass)
129
130
  klass.ransackable_attributes(auth_object).include?(str) ||
130
- klass.ransortable_attributes(auth_object).include?(str)
131
+ klass.ransortable_attributes(auth_object).include?(str)
131
132
  end
132
133
 
133
134
  def ransackable_association?(str, klass)
@@ -7,17 +7,11 @@ module ActionView::Helpers::Tags
7
7
  class Base
8
8
  private
9
9
  if defined? ::ActiveRecord
10
- if ::ActiveRecord::VERSION::STRING < '5.2'
11
- def value(object)
12
- object.send @method_name if object # use send instead of public_send
13
- end
14
- else # rails/rails#29791
15
- def value
16
- if @allow_method_names_outside_object
17
- object.send @method_name if object && object.respond_to?(@method_name, true)
18
- else
19
- object.send @method_name if object
20
- end
10
+ def value
11
+ if @allow_method_names_outside_object
12
+ object.send @method_name if object && object.respond_to?(@method_name, true)
13
+ else
14
+ object.send @method_name if object
21
15
  end
22
16
  end
23
17
  end
@@ -145,7 +145,7 @@ module Ransack
145
145
  private
146
146
 
147
147
  def parameters_hash(params)
148
- if ::ActiveRecord::VERSION::MAJOR == 5 && params.respond_to?(:to_unsafe_h)
148
+ if ::ActiveRecord::VERSION::MAJOR >= 5 && params.respond_to?(:to_unsafe_h)
149
149
  params.to_unsafe_h
150
150
  else
151
151
  params
@@ -0,0 +1,70 @@
1
+ ar:
2
+ ransack:
3
+ search: "بحث"
4
+ predicate: "فاعل"
5
+ and: "و"
6
+ or: "أو"
7
+ any: "أيُّ"
8
+ all: "كل"
9
+ combinator: "دالة توافقية"
10
+ attribute: "خاصية"
11
+ value: "قيمة"
12
+ condition: "شرط"
13
+ sort: "ترتيب"
14
+ asc: "تصاعدي"
15
+ desc: "تنازلي"
16
+ predicates:
17
+ eq: "معادل"
18
+ eq_any: "معادل على اﻷقل لواحد"
19
+ eq_all: "معادل للجميع"
20
+ not_eq: "ليس معادلا لـ"
21
+ not_eq_any: "ليس معادلا على اﻷقل لواحد"
22
+ not_eq_all: "ليس معادلا للجميع"
23
+ matches: "موائم"
24
+ matches_any: "موائم لواحد على اﻷقل"
25
+ matches_all: "موائم للجميع"
26
+ does_not_match: "لا يتواءم"
27
+ does_not_match_any: "لا يتواءم مع واحد على اﻷقل"
28
+ does_not_match_all: "لا يتواءم مع الجميع"
29
+ lt: "أصغر من"
30
+ lt_any: "أصغر لواحد على اﻷقل"
31
+ lt_all: "أصغر من الجميع"
32
+ lteq: "أصغر أو مساو لـ"
33
+ lteq_any: "أصغر أو مساو لواحد على اﻷقل"
34
+ lteq_all: "أصغر أو مساو للجميع"
35
+ gt: "أكبر من"
36
+ gt_any: "أكبر من واحد على اﻷقل"
37
+ gt_all: "أكبر من الجميع"
38
+ gteq: "أكبر أو مساو لـ"
39
+ gteq_any: "أكبر أو مساو لواحد على اﻷقل"
40
+ gteq_all: "أكبر أو مساو للجميع"
41
+ in: "متضمن لـ"
42
+ in_any: "متضمن لواحد على اﻷقل"
43
+ in_all: "متضمن للجميع"
44
+ not_in: "غير متضمن"
45
+ not_in_any: "غير متضمن لواحد على اﻷقل"
46
+ not_in_all: "غير متضمن للجميع"
47
+ cont: "محتو"
48
+ cont_any: "محتو لواحد على اﻷقل"
49
+ cont_all: "محتو لجميع"
50
+ not_cont: "غير محتو"
51
+ not_cont_any: "غير محتو لواحد على اﻷقل"
52
+ not_cont_all: "غير محتو للجميع"
53
+ start: "يبدأ بـ"
54
+ start_any: "يبدأ بواحد على اﻷقل"
55
+ start_all: "يبدأ بالجميع"
56
+ not_start: "لا يبدأ بـ"
57
+ not_start_any: "لا يبدأ بواحد على اﻷقل"
58
+ not_start_all: "لا يبدأ بالجميع"
59
+ end: "ينتهي بـ"
60
+ end_any: "ينتهي بواحد على اﻷقل"
61
+ end_all: "ينتهي بالجميع"
62
+ not_end: "لا ينتهي بـ"
63
+ not_end_any: "لا ينتهي بواحد على اﻷقل"
64
+ not_end_all: "لا ينتهي بالجميع"
65
+ 'true': "صحيح"
66
+ 'false': "خطأ"
67
+ present: "مستقبل"
68
+ blank: "فراغ"
69
+ 'null': "عدم"
70
+ not_null: "غير مساو لقيمة عدم"
@@ -1,4 +1,4 @@
1
- tr:
1
+ az:
2
2
  ransack:
3
3
  search: "axtar"
4
4
  predicate: "təsdiqlə"
@@ -0,0 +1,70 @@
1
+ ca:
2
+ ransack:
3
+ search: "cercar"
4
+ predicate: "predicat"
5
+ and: "i"
6
+ or: "o"
7
+ any: "qualsevol"
8
+ all: "tots"
9
+ combinator: "combinador"
10
+ attribute: "atribut"
11
+ value: "valor"
12
+ condition: "condició"
13
+ sort: "ordenar"
14
+ asc: "ascendent"
15
+ desc: "descendent"
16
+ predicates:
17
+ eq: "és igual a"
18
+ eq_any: "és igual a qualsevol"
19
+ eq_all: "és igual a tots"
20
+ not_eq: "no és igual a"
21
+ not_eq_any: "no és igual a qualsevol"
22
+ not_eq_all: "no és igual a tots"
23
+ matches: "coincideix"
24
+ matches_any: "coincideix a qualsevol"
25
+ matches_all: "coincideix a tots"
26
+ does_not_match: "no coincideix"
27
+ does_not_match_any: "no coincideix amb cap"
28
+ does_not_match_all: "no coincideix amb tots"
29
+ lt: "menor que"
30
+ lt_any: "menor que qualsevol"
31
+ lt_all: "menor o igual a"
32
+ lteq: "menor que o igual a"
33
+ lteq_any: "menor o igual a qualsevol"
34
+ lteq_all: "menor o igual a tots"
35
+ gt: "major que"
36
+ gt_any: "major que qualsevol"
37
+ gt_all: "major que tots"
38
+ gteq: "major que o igual a"
39
+ gteq_any: "major que o igual a qualsevol"
40
+ gteq_all: "major que o igual a tots"
41
+ in: "en"
42
+ in_any: "en qualsevol"
43
+ in_all: "en tots"
44
+ not_in: "no en"
45
+ not_in_any: "no en qualsevol"
46
+ not_in_all: "no en tots"
47
+ cont: "conté"
48
+ cont_any: "conté qualsevol"
49
+ cont_all: "conté tots"
50
+ not_cont: "no conté"
51
+ not_cont_any: "no conté cap"
52
+ not_cont_all: "no conté tota"
53
+ start: "comença per"
54
+ start_any: "comença per qualsevol"
55
+ start_all: "comença per tot"
56
+ not_start: "no comença per"
57
+ not_start_any: "no comença per qualsevol"
58
+ not_start_all: "no comença per tot"
59
+ end: "acaba en"
60
+ end_any: "acaba en qualsevol"
61
+ end_all: "acaba en tot"
62
+ not_end: "no acaba en"
63
+ not_end_any: "no acaba en qualsevol"
64
+ not_end_all: "no acaba en tot"
65
+ 'true': "és verdader"
66
+ 'false': "és fals"
67
+ present: "és present"
68
+ blank: "està en blanc"
69
+ 'null': "és nul"
70
+ not_null: "no és nul"
@@ -6,11 +6,11 @@ es:
6
6
  or: "o"
7
7
  any: "cualquier"
8
8
  all: "todos"
9
- combinator: "combinado"
9
+ combinator: "combinador"
10
10
  attribute: "atributo"
11
11
  value: "valor"
12
12
  condition: "condición"
13
- sort: "ordernar"
13
+ sort: "ordenar"
14
14
  asc: "ascendente"
15
15
  desc: "descendente"
16
16
  predicates:
@@ -19,12 +19,12 @@ es:
19
19
  eq_all: "es igual a todos"
20
20
  not_eq: "no es igual a"
21
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"
22
+ not_eq_all: "no es igual a todos"
23
+ matches: "coincide con"
24
+ matches_any: "coincide con cualquier"
25
+ matches_all: "coincide con todos"
26
+ does_not_match: "no coincide con"
27
+ does_not_match_any: "no coincide con ninguno"
28
28
  does_not_match_all: "no coincide con todos"
29
29
  lt: "menor que"
30
30
  lt_any: "menor que cualquier"
@@ -48,23 +48,23 @@ es:
48
48
  cont_any: "contiene cualquier"
49
49
  cont_all: "contiene todos"
50
50
  not_cont: "no contiene"
51
- not_cont_any: "no contiene ninguna"
52
- not_cont_all: "no contiene toda"
51
+ not_cont_any: "no contiene ninguno"
52
+ not_cont_all: "no contiene todos"
53
53
  start: "comienza con"
54
54
  start_any: "comienza con cualquier"
55
- start_all: "comienza con toda"
56
- not_start: "no inicia con"
55
+ start_all: "comienza con todos"
56
+ not_start: "no comienza con"
57
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"
58
+ not_start_all: "no comienza con todos"
59
+ end: "termina en"
60
+ end_any: "termina en cualquier"
61
+ end_all: "termina en todos"
62
+ not_end: "no termina en"
63
+ not_end_any: "no termina en cualquier"
64
+ not_end_all: "no termina en todos"
65
65
  'true': "es verdadero"
66
66
  'false': "es falso"
67
- present: "es presente"
67
+ present: "está presente"
68
68
  blank: "está en blanco"
69
- 'null': "es nula"
70
- not_null: "no es nula"
69
+ 'null': "es nulo"
70
+ not_null: "no es nulo"
@@ -0,0 +1,70 @@
1
+ fa:
2
+ ransack:
3
+ search: "جستجو"
4
+ predicate: "پیش فرض"
5
+ and: "و"
6
+ or: "یا"
7
+ any: "هر کدام"
8
+ all: "همه"
9
+ combinator: "ترکیب کننده"
10
+ attribute: "ویژگی"
11
+ value: "مقدار"
12
+ condition: "شرایط"
13
+ sort: "مرتب سازی"
14
+ asc: "صعودی"
15
+ desc: "نزولی"
16
+ predicates:
17
+ eq: "مساوی با"
18
+ eq_any: "مساوی با حداقل یکی"
19
+ eq_all: "مساوی با همه"
20
+ not_eq: "غیر مساوی با"
21
+ not_eq_any: "غیر مساوی با هیچ کدام"
22
+ not_eq_all: "غیر مساوی با همه"
23
+ matches: "مشابهات"
24
+ matches_any: "شبیه حداقل یکی"
25
+ matches_all: "شبیه همه"
26
+ does_not_match: "بدون شباهت"
27
+ does_not_match_any: "شبیه یکی هم نیست"
28
+ does_not_match_all: "شبیه هیچ کدام نیست"
29
+ lt: "کمتر از"
30
+ lt_any: "کمتر از حداقل یکی"
31
+ lt_all: "کمتر از همه"
32
+ lteq: "کمتر یا مساوی با"
33
+ lteq_any: "کمتر یا مساوی با حداقل یکی"
34
+ lteq_all: "کمتر یا مساوی با همه"
35
+ gt: "بیشتر از"
36
+ gt_any: "بیشتر از حداقل یکی"
37
+ gt_all: "بیشتر از همه"
38
+ gteq: "بیشتر یا مساوی با"
39
+ gteq_any: "بیشتر یا مساوی با حداقل یکی"
40
+ gteq_all: "بیشتر یا مساوی با همه"
41
+ in: "در"
42
+ in_any: "در حداقل یکی"
43
+ in_all: "در همه"
44
+ not_in: "نه در"
45
+ not_in_any: "نه حتی در یکی"
46
+ not_in_all: "در هیچ کدام"
47
+ cont: "حاوی"
48
+ cont_any: "حاوی حداقل یکی"
49
+ cont_all: "حاوی همه"
50
+ not_cont: "حاوی این نمیشود"
51
+ not_cont_any: "حاوی حتی یکی هم نمیشود"
52
+ not_cont_all: "حاوی هیچ کدام نمیشود"
53
+ start: "شروع می شود با"
54
+ start_any: "شروع می شود با حداقل یکی"
55
+ start_all: "شروع می شود با همه"
56
+ not_start: "شروع نمی شود با"
57
+ not_start_any: "شروع نمی شود با حتی یکی"
58
+ not_start_all: "شروع نمی شود با هیچ کدام"
59
+ end: "به پایان می رسد با"
60
+ end_any: "به پایان می رسد با حداقل یکی"
61
+ end_all: "به پایان می رسد با همه"
62
+ not_end: "پایان نمی یابد با"
63
+ not_end_any: "پایان نمی یابد با حتی یکی"
64
+ not_end_all: "پایان نمی یابد با هیچ کدام"
65
+ 'true': "درست است"
66
+ 'false': "نادرست است"
67
+ present: "موجود است"
68
+ blank: "خالی است"
69
+ 'null': "صفر است"
70
+ not_null: "صفر نیست"