[{{mminutes}}:{{sseconds}}] X
Пользователь приглашает вас присоединиться к открытой игре игре с друзьями .
Ruby on Rails random LOC
(1)       Используют 17 человек

Комментарии

Ни одного комментария.
Написать тут
Описание:
Ruby on Rails random LOC
Автор:
AccuracyFirst
Создан:
30 апреля 2016 в 08:39
Публичный:
Нет
Тип словаря:
Фразы
В этом режиме перемешиваться будут не слова, а целые фразы, разделенные переносом строки.
Информация:
Ruby on Rails random LOC
Содержание:
1 module Arel
2 module AliasPredication
3 def as other
4 Nodes::As.new self, Nodes::SqlLiteral.new(other)
5 end
6 end
7 endmodule Arel
8 module Attributes
9 class Attribute Struct.new :relation, :name
10 include Arel::Expressions
11 include Arel::Predications
12 include Arel::AliasPredication
13 include Arel::OrderPredications
14 include Arel::Math
15 def lower
16 relation.lower self
17 end
18 def type_cast_for_database(value)
19 relation.type_cast_for_database(name, value)
20 end
21 def able_to_type_cast?
22 relation.able_to_type_cast?
23 end
24 end
25 class String Attribute; end
26 class Time Attribute; end
27 class Boolean Attribute; end
28 class Decimal Attribute; end
29 class Float Attribute; end
30 class Integer Attribute; end
31 class Undefined Attribute; end
32 end
33 Attribute = Attributes::Attribute
34 end
35 require 'arel/attributes/attribute'
36 module Arel
37 module Attributes
38 def self.for column
39 case column.type
40 when :string, :text, :binary then String
41 when :integer then Integer
42 when :float then Float
43 when :decimal then Decimal
44 when :boolean then Boolean
45 else
46 Undefined
47 end
48 end
49 end
50 end
51 module Arel
52 module Collectors
53 class Bind
54 def initialize
55 @parts = []
56 end
57 def str
58 @parts str
59 self
60 end
61 def add_bind bind
62 @parts bind
63 self
64 end
65 def value; @parts; end
66 def substitute_binds bvs
67 bvs = bvs.dup
68 @parts.map do |val|
69 if Arel::Nodes::BindParam === val
70 bvs.shift
71 else
72 val
73 end
74 end
75 end
76 def compile bvs
77 substitute_binds(bvs).join
78 end
79 end
80 end
81 end
82 module Arel
83 module Collectors
84 class PlainString
85 def initialize
86 @str = ''
87 end
88 def value
89 @str
90 end
91 def str
92 @str str
93 self
94 end
95 end
96 end
97 end
98 require 'arel/collectors/plain_string'
99 module Arel
100 module Collectors
101 class SQLString PlainString
102 def initialize(*)
103 super
104 @bind_index = 1
105 end
106 def add_bind bind
107 self yield(@bind_index)
108 @bind_index += 1
109 self
110 end
111 def compile bvs
112 value
113 end
114 end
115 end
116 end
117 module Arel
118 module Compatibility # :nodoc:
119 class Wheres # :nodoc:
120 include Enumerable
121 module Value # :nodoc:
122 attr_accessor :visitor
123 def value
124 visitor.accept self
125 end
126 def name
127 super.to_sym
128 end
129 end
130 def initialize engine, collection
131 @engine = engine
132 @collection = collection
133 end
134 def each
135 to_sql = Visitors::ToSql.new @engine
136 @collection.each { |c|
137 c.extend(Value)
138 c.visitor = to_sql
139 yield c
140 }
141 end
142 end
143 end
144 end
145 module Arel
146 module Crud
147 def compile_update values, pk
148 um = UpdateManager.new
149 if Nodes::SqlLiteral === values
150 relation = @ctx.from
151 else
152 relation = values.first.first.relation
153 end
154 um.key = pk
155 um.table relation
156 um.set values
157 um.take @ast.limit.expr if @ast.limit
158 um.order(*@ast.orders)
159 um.wheres = @ctx.wheres
160 um
161 end
162 def compile_insert values
163 im = create_insert
164 im.insert values
165 im
166 end
167 def create_insert
168 InsertManager.new
169 end
170 def compile_delete
171 dm = DeleteManager.new
172 dm.wheres = @ctx.wheres
173 dm.from @ctx.froms
174 dm
175 end
176 end
177 end
178 module Arel
179 class DeleteManager Arel::TreeManager
180 def initialize
181 super
182 @ast = Nodes::DeleteStatement.new
183 @ctx = @ast
184 end
185 def from relation
186 @ast.relation = relation
187 self
188 end
189 def wheres= list
190 @ast.wheres = list
191 end
192 end
193 end
194 module Arel
195 module Expressions
196 def count distinct = false
197 Nodes::Count.new [self], distinct
198 end
199 def sum
200 Nodes::Sum.new [self]
201 end
202 def maximum
203 Nodes::Max.new [self]
204 end
205 def minimum
206 Nodes::Min.new [self]
207 end
208 def average
209 Nodes::Avg.new [self]
210 end
211 def extract field
212 Nodes::Extract.new [self], field
213 end
214 end
215 end
216 module Arel
217 module FactoryMethods
218 def create_true
219 Arel::Nodes::True.new
220 end
221 def create_false
222 Arel::Nodes::False.new
223 end
224 def create_table_alias relation, name
225 Nodes::TableAlias.new(relation, name)
226 end
227 klass.new(to, constraint)
228 end
229 def create_string_join to
230 create_join to, nil, Nodes::StringJoin
231 end
232 def create_and clauses
233 Nodes::And.new clauses
234 end
235 def create_on expr
236 Nodes::On.new expr
237 end
238 def grouping expr
239 Nodes::Grouping.new expr
240 end
241 def lower column
242 end
243 end
244 end
245 module Arel
246 class InsertManager Arel::TreeManager
247 def initialize
248 super
249 @ast = Nodes::InsertStatement.new
250 end
251 def into table
252 @ast.relation = table
253 self
254 end
255 def columns; @ast.columns end
256 def values= val; @ast.values = val; end
257 def select select
258 @ast.select = select
259 end
260 def insert fields
261 return if fields.empty?
262 if String === fields
263 @ast.values = Nodes::SqlLiteral.new(fields)
264 else
265 @ast.relation ||= fields.first.first.relation
266 values = []
267 fields.each do |column, value|
268 @ast.columns column
269 values value
270 end
271 @ast.values = create_values values, @ast.columns
272 end
273 end
274 def create_values values, columns
275 Nodes::Values.new values, columns
276 end
277 end
278 end
279 module Arel
280 module Math
281 def *(other)
282 Arel::Nodes::Multiplication.new(self, other)
283 end
284 def +(other)
285 end
286 def -(other)
287 end
288 def /(other)
289 Arel::Nodes::Division.new(self, other)
290 end
291 end
292 end
293 module Arel
294 module Nodes
295 class And Arel::Nodes::Node
296 attr_reader :children
297 def initialize children
298 super()
299 @children = children
300 end
301 def left
302 children.first
303 end
304 def right
305 children[1]
306 end
307 def hash
308 children.hash
309 end
310 def eql? other
311 self.class == other.class &&
312 self.children == other.children
313 end
314 alias :== :eql?
315 end
316 end
317 end
318 module Arel
319 module Nodes
320 class Ascending Ordering
321 def reverse
322 Descending.new(expr)
323 end
324 def direction
325 :asc
326 end
327 def ascending?
328 true
329 end
330 def descending?
331 false
332 end
333 end
334 end
335 end
336 module Arel
337 module Nodes
338 class Binary Arel::Nodes::Node
339 attr_accessor :left, :right
340 def initialize left, right
341 super()
342 @left = left
343 @right = right
344 end
345 def initialize_copy other
346 super
347 @left = @left.clone if @left
348 @right = @right.clone if @right
349 end
350 def hash
351 [self.class, @left, @right].hash
352 end
353 def eql? other
354 self.class == other.class &&
355 self.left == other.left &&
356 self.right == other.right
357 end
358 alias :== :eql?
359 end
360 %w{
361 As
362 Assignment
363 Between
364 GreaterThan
365 GreaterThanOrEqual
366 Join
367 LessThan
368 LessThanOrEqual
369 NotEqual
370 NotIn
371 NotRegexp
372 Or
373 Regexp
374 Union
375 UnionAll
376 Intersect
377 Except
378 }.each do |name|
379 const_set name, Class.new(Binary)
380 end
381 end
382 end
383 module Arel
384 module Nodes
385 class BindParam Node
386 def ==(other)
387 other.is_a?(BindParam)
388 end
389 end
390 end
391 end
392 module Arel
393 module Nodes
394 class Count Arel::Nodes::Function
395 super(expr, aliaz)
396 @distinct = distinct
397 end
398 end
399 end
400 end
401 module Arel
402 module Nodes
403 class DeleteStatement Arel::Nodes::Binary
404 alias :relation :left
405 alias :relation= :left=
406 alias :wheres :right
407 alias :wheres= :right=
408 def initialize relation = nil, wheres = []
409 super
410 end
411 def initialize_copy other
412 super
413 @right = @right.clone
414 end
415 end
416 end
417 end
418 module Arel
419 module Nodes
420 class Descending Ordering
421 def reverse
422 Ascending.new(expr)
423 end
424 def direction
425 :desc
426 end
427 def ascending?
428 false
429 end
430 def descending?
431 true
432 end
433 end
434 end
435 end
436 module Arel
437 module Nodes
438 class Equality Arel::Nodes::Binary
439 def operator; :== end
440 alias :operand1 :left
441 alias :operand2 :right
442 end
443 end
444 end
445 module Arel
446 module Nodes
447 class Extract Arel::Nodes::Unary
448 include Arel::AliasPredication
449 include Arel::Predications
450 attr_accessor :field
451 def initialize expr, field
452 super(expr)
453 @field = field
454 end
455 def hash
456 super ^ @field.hash
457 end
458 def eql? other
459 super &&
460 self.field == other.field
461 end
462 alias :== :eql?
463 end
464 end
465 end
466 module Arel
467 module Nodes
468 class False Arel::Nodes::Node
469 def hash
470 self.class.hash
471 end
472 def eql? other
473 self.class == other.class
474 end
475 end
476 end
477 end
478 module Arel
479 module Nodes
480 class FullOuterJoin Arel::Nodes::Join
481 end
482 end
483 end
484 module Arel
485 module Nodes
486 class Function Arel::Nodes::Node
487 include Arel::Predications
488 include Arel::WindowPredications
489 attr_accessor :expressions, :alias, :distinct
490 def initialize expr, aliaz = nil
491 super()
492 @expressions = expr
493 @alias = aliaz && SqlLiteral.new(aliaz)
494 @distinct = false
495 end
496 def as aliaz
497 self.alias = SqlLiteral.new(aliaz)
498 self
499 end
500 def hash
501 [@expressions, @alias, @distinct].hash
502 end
503 def eql? other
504 self.class == other.class &&
505 self.expressions == other.expressions &&
506 self.alias == other.alias &&
507 self.distinct == other.distinct
508 end
509 end
510 %w{
511 Sum
512 Exists
513 Max
514 Min
515 Avg
516 }.each do |name|
517 const_set(name, Class.new(Function))
518 end
519 end
520 end
521 module Arel
522 module Nodes
523 class Grouping Unary
524 include Arel::Predications
525 end
526 end
527 end
528 module Arel
529 module Nodes
530 class In Equality
531 end
532 end
533 end
534 module Arel
535 module Nodes
536 class InfixOperation Binary
537 include Arel::Expressions
538 include Arel::Predications
539 include Arel::OrderPredications
540 include Arel::AliasPredication
541 include Arel::Math
542 attr_reader :operator
543 def initialize operator, left, right
544 super(left, right)
545 @operator = operator
546 end
547 end
548 class Multiplication InfixOperation
549 def initialize left, right
550 super(:*, left, right)
551 end
552 end
553 class Division InfixOperation
554 def initialize left, right
555 super(:/, left, right)
556 end
557 end
558 class Addition InfixOperation
559 def initialize left, right
560 super(:+, left, right)
561 end
562 end
563 class Subtraction InfixOperation
564 def initialize left, right
565 super(:-, left, right)
566 end
567 end
568 end
569 endmodule Arel
570 module Nodes
571 class InnerJoin Arel::Nodes::Join
572 end
573 end
574 end
575 module Arel
576 module Nodes
577 class InsertStatement Arel::Nodes::Node
578 def initialize
579 super()
580 @relation = nil
581 @columns = []
582 @values = nil
583 @select = nil
584 end
585 def initialize_copy other
586 super
587 @columns = @columns.clone
588 @values = @values.clone if @values
589 @select = @select.clone if @select
590 end
591 def hash
592 [@relation, @columns, @values, @select].hash
593 end
594 def eql? other
595 self.class == other.class &&
596 self.relation == other.relation &&
597 self.columns == other.columns &&
598 self.select == other.select &&
599 self.values == other.values
600 end
601 alias :== :eql?
602 end
603 end
604 end
605 module Arel
606 module Nodes
607 class JoinSource Arel::Nodes::Binary
608 def initialize single_source, joinop = []
609 super
610 end
611 def empty?
612 !left && right.empty?
613 end
614 end
615 end
616 end
617 module Arel
618 module Nodes
619 class Matches Binary
620 attr_reader :escape
621 def initialize(left, right, escape = nil)
622 super(left, right)
623 @escape = escape && Nodes.build_quoted(escape)
624 end
625 end
626 class DoesNotMatch Matches; end
627 end
628 end
629 module Arel
630 module Nodes
631 class NamedFunction Arel::Nodes::Function
632 attr_accessor :name
633 def initialize name, expr, aliaz = nil
634 super(expr, aliaz)
635 @name = name
636 end
637 def hash
638 super ^ @name.hash
639 end
640 def eql? other
641 super && self.name == other.name
642 end
643 alias :== :eql?
644 end
645 end
646 end
647 require 'arel/collectors/sql_string'
648 module Arel
649 module Nodes
650 class Node
651 include Arel::FactoryMethods
652 include Enumerable
653 if $DEBUG
654 def _caller
655 @caller
656 end
657 def initialize
658 @caller = caller.dup
659 end
660 end
661 def not
662 Nodes::Not.new self
663 end
664 def or right
665 Nodes::Grouping.new Nodes::Or.new(self, right)
666 end
667 def and right
668 Nodes::And.new [self, right]
669 end
670 def to_sql engine = Table.engine
671 collector = Arel::Collectors::SQLString.new
672 collector.value
673 end
674 def each &block
675 return enum_for(:each) unless block_given?
676 end
677 end
678 end
679 end
680 module Arel
681 module Nodes
682 class OuterJoin Arel::Nodes::Join
683 end
684 end
685 end
686 module Arel
687 module Nodes
688 class Over Binary
689 include Arel::AliasPredication
690 def initialize(left, right = nil)
691 super(left, right)
692 end
693 def operator; 'OVER' end
694 end
695 end
696 endmodule Arel
697 module Nodes
698 class RightOuterJoin Arel::Nodes::Join
699 end
700 end
701 end
702 module Arel
703 module Nodes
704 class SelectCore Arel::Nodes::Node
705 attr_accessor :havings, :source, :set_quantifier
706 def initialize
707 super()
708 @source = JoinSource.new nil
709 @top = nil
710 @set_quantifier = nil
711 @projections = []
712 @wheres = []
713 @groups = []
714 @havings = []
715 @windows = []
716 end
717 def from
718 @source.left
719 end
720 def from= value
721 @source.left = value
722 end
723 alias :froms= :from=
724 alias :froms :from
725 def initialize_copy other
726 super
727 @source = @source.clone if @source
728 @projections = @projections.clone
729 @wheres = @wheres.clone
730 @groups = @groups.clone
731 @havings = @havings.clone
732 @windows = @windows.clone
733 end
734 def hash
735 [
736 @source, @top, @set_quantifier, @projections,
737 @wheres, @groups, @havings, @windows
738 ].hash
739 end
740 def eql? other
741 self.class == other.class &&
742 self.source == other.source &&
743 self.top == other.top &&
744 self.set_quantifier == other.set_quantifier &&
745 self.projections == other.projections &&
746 self.wheres == other.wheres &&
747 self.groups == other.groups &&
748 self.havings == other.havings &&
749 self.windows == other.windows
750 end
751 alias :== :eql?
752 end
753 end
754 end
755 module Arel
756 module Nodes
757 class SelectStatement Arel::Nodes::Node
758 attr_reader :cores
759 def initialize cores = [SelectCore.new]
760 super()
761 @cores = cores
762 @orders = []
763 @limit = nil
764 @lock = nil
765 @offset = nil
766 @with = nil
767 end
768 def initialize_copy other
769 super
770 @cores = @cores.map { |x| x.clone }
771 @orders = @orders.map { |x| x.clone }
772 end
773 def hash
774 end
775 def eql? other
776 self.class == other.class &&
777 self.cores == other.cores &&
778 self.orders == other.orders &&
779 self.limit == other.limit &&
780 self.lock == other.lock &&
781 self.offset == other.offset &&
782 self.with == other.with
783 end
784 alias :== :eql?
785 end
786 end
787 end
788 module Arel
789 module Nodes
790 class SqlLiteral String
791 include Arel::Expressions
792 include Arel::Predications
793 include Arel::AliasPredication
794 include Arel::OrderPredications
795 def encode_with(coder)
796 coder.scalar = self.to_s
797 end
798 end
799 end
800 end
801 module Arel
802 module Nodes
803 class StringJoin Arel::Nodes::Join
804 def initialize left, right = nil
805 super
806 end
807 end
808 end
809 end
810 module Arel
811 module Nodes
812 class TableAlias Arel::Nodes::Binary
813 alias :name :right
814 alias :relation :left
815 alias :table_alias :name
816 def [] name
817 Attribute.new(self, name)
818 end
819 def table_name
820 end
821 def type_cast_for_database(*args)
822 relation.type_cast_for_database(*args)
823 end
824 def able_to_type_cast?
825 end
826 end
827 end
828 end
829 module Arel
830 module Nodes
831 class Distinct Arel::Nodes::Node
832 def hash
833 self.class.hash
834 end
835 def eql? other
836 self.class == other.class
837 end
838 end
839 end
840 end
841 module Arel
842 module Nodes
843 class True Arel::Nodes::Node
844 def hash
845 self.class.hash
846 end
847 def eql? other
848 self.class == other.class
849 end
850 end
851 end
852 end
853 module Arel
854 module Nodes
855 class Unary Arel::Nodes::Node
856 attr_accessor :expr
857 alias :value :expr
858 def initialize expr
859 super()
860 @expr = expr
861 end
862 def hash
863 @expr.hash
864 end
865 def eql? other
866 self.class == other.class &&
867 self.expr == other.expr
868 end
869 alias :== :eql?
870 end
871 %w{
872 Bin
873 Group
874 Limit
875 Not
876 Offset
877 On
878 Ordering
879 Top
880 Lock
881 DistinctOn
882 }.each do |name|
883 const_set(name, Class.new(Unary))
884 end
885 end
886 end
887 module Arel
888 module Nodes
889 class UnqualifiedColumn Arel::Nodes::Unary
890 alias :attribute :expr
891 alias :attribute= :expr=
892 def relation
893 @expr.relation
894 end
895 def column
896 @expr.column
897 end
898 def name
899 @expr.name
900 end
901 end
902 end
903 end
904 module Arel
905 module Nodes
906 class UpdateStatement Arel::Nodes::Node
907 attr_accessor :key
908 def initialize
909 @relation = nil
910 @wheres = []
911 @values = []
912 @orders = []
913 @limit = nil
914 @key = nil
915 end
916 def initialize_copy other
917 super
918 @wheres = @wheres.clone
919 @values = @values.clone
920 end
921 def hash
922 end
923 def eql? other
924 self.class == other.class &&
925 self.relation == other.relation &&
926 self.wheres == other.wheres &&
927 self.values == other.values &&
928 self.orders == other.orders &&
929 self.limit == other.limit &&
930 self.key == other.key
931 end
932 alias :== :eql?
933 end
934 end
935 end
936 module Arel
937 module Nodes
938 class Values Arel::Nodes::Binary
939 alias :expressions :left
940 alias :expressions= :left=
941 alias :columns :right
942 alias :columns= :right=
943 def initialize exprs, columns = []
944 super
945 end
946 end
947 end
948 end
949 module Arel
950 module Nodes
951 class Window Arel::Nodes::Node
952 attr_accessor :orders, :framing, :partitions
953 def initialize
954 @orders = []
955 @partitions = []
956 @framing = nil
957 end
958 def order *expr
959 @orders.concat expr.map { |x|
960 }
961 self
962 end
963 def partition *expr
964 @partitions.concat expr.map { |x|
965 }
966 self
967 end
968 def frame(expr)
969 @framing = expr
970 end
971 def rows(expr = nil)
972 if @framing
973 Rows.new(expr)
974 else
975 frame(Rows.new(expr))
976 end
977 end
978 def range(expr = nil)
979 if @framing
980 Range.new(expr)
981 else
982 frame(Range.new(expr))
983 end
984 end
985 def initialize_copy other
986 super
987 @orders = @orders.map { |x| x.clone }
988 end
989 def hash
990 [@orders, @framing].hash
991 end
992 def eql? other
993 self.class == other.class &&
994 self.orders == other.orders &&
995 self.framing == other.framing &&
996 self.partitions == other.partitions
997 end
998 alias :== :eql?
999 end
1000 class NamedWindow Window
1001 attr_accessor :name
1002 def initialize name
1003 super()
1004 @name = name
1005 end
1006 def initialize_copy other
1007 super
1008 @name = other.name.clone
1009 end
1010 def hash
1011 super ^ @name.hash
1012 end
1013 def eql? other
1014 super && self.name == other.name
1015 end
1016 alias :== :eql?
1017 end
1018 class Rows Unary
1019 def initialize(expr = nil)
1020 super(expr)
1021 end
1022 end
1023 class Range Unary
1024 def initialize(expr = nil)
1025 super(expr)
1026 end
1027 end
1028 class CurrentRow Node
1029 def hash
1030 self.class.hash
1031 end
1032 def eql? other
1033 self.class == other.class
1034 end
1035 end
1036 class Preceding Unary
1037 def initialize(expr = nil)
1038 super(expr)
1039 end
1040 end
1041 class Following Unary
1042 def initialize(expr = nil)
1043 super(expr)
1044 end
1045 end
1046 end
1047 end
1048 module Arel
1049 module Nodes
1050 class With Arel::Nodes::Unary
1051 alias children expr
1052 end
1053 class WithRecursive With; end
1054 end
1055 end
1056 require 'arel/nodes/node'
1057 require 'arel/nodes/select_statement'
1058 require 'arel/nodes/select_core'
1059 require 'arel/nodes/insert_statement'
1060 require 'arel/nodes/update_statement'
1061 require 'arel/nodes/bind_param'
1062 require 'arel/nodes/terminal'
1063 require 'arel/nodes/true'
1064 require 'arel/nodes/false'
1065 require 'arel/nodes/unary'
1066 require 'arel/nodes/grouping'
1067 require 'arel/nodes/ascending'
1068 require 'arel/nodes/descending'
1069 require 'arel/nodes/unqualified_column'
1070 require 'arel/nodes/with'
1071 require 'arel/nodes/binary'
1072 require 'arel/nodes/equality'
1073 require 'arel/nodes/join_source'
1074 require 'arel/nodes/delete_statement'
1075 require 'arel/nodes/table_alias'
1076 require 'arel/nodes/infix_operation'
1077 require 'arel/nodes/over'
1078 require 'arel/nodes/matches'
1079 require 'arel/nodes/and'
1080 require 'arel/nodes/function'
1081 require 'arel/nodes/count'
1082 require 'arel/nodes/extract'
1083 require 'arel/nodes/values'
1084 require 'arel/nodes/named_function'
1085 require 'arel/nodes/window'
1086 require 'arel/nodes/full_outer_join'
1087 require 'arel/nodes/inner_join'
1088 require 'arel/nodes/outer_join'
1089 require 'arel/nodes/right_outer_join'
1090 require 'arel/nodes/string_join'
1091 require 'arel/nodes/sql_literal'
1092 module Arel
1093 module Nodes
1094 class Casted Arel::Nodes::Node # :nodoc:
1095 attr_reader :val, :attribute
1096 def initialize val, attribute
1097 @val = val
1098 @attribute = attribute
1099 super()
1100 end
1101 def nil?; @val.nil?; end
1102 def eql? other
1103 self.class == other.class &&
1104 self.val == other.val &&
1105 self.attribute == other.attribute
1106 end
1107 alias :== :eql?
1108 end
1109 class Quoted Arel::Nodes::Unary # :nodoc:
1110 alias :val :value
1111 def nil?; val.nil?; end
1112 end
1113 def self.build_quoted other, attribute = nil
1114 case other
1115 other
1116 else
1117 case attribute
1118 when Arel::Attributes::Attribute
1119 Casted.new other, attribute
1120 else
1121 Quoted.new other
1122 end
1123 end
1124 end
1125 end
1126 end
1127 module Arel
1128 module OrderPredications
1129 def asc
1130 Nodes::Ascending.new self
1131 end
1132 def desc
1133 Nodes::Descending.new self
1134 end
1135 end
1136 end
1137 module Arel
1138 module Predications
1139 def not_eq other
1140 Nodes::NotEqual.new self, quoted_node(other)
1141 end
1142 def not_eq_any others
1143 grouping_any :not_eq, others
1144 end
1145 def not_eq_all others
1146 grouping_all :not_eq, others
1147 end
1148 def eq other
1149 Nodes::Equality.new self, quoted_node(other)
1150 end
1151 def eq_any others
1152 grouping_any :eq, others
1153 end
1154 def eq_all others
1155 grouping_all :eq, quoted_array(others)
1156 end
1157 def between other
1158 if equals_quoted?(other.begin, -Float::INFINITY)
1159 if equals_quoted?(other.end, Float::INFINITY)
1160 not_in([])
1161 elsif other.exclude_end?
1162 lt(other.end)
1163 else
1164 lteq(other.end)
1165 end
1166 elsif equals_quoted?(other.end, Float::INFINITY)
1167 gteq(other.begin)
1168 elsif other.exclude_end?
1169 gteq(other.begin).and(lt(other.end))
1170 else
1171 left = quoted_node(other.begin)
1172 right = quoted_node(other.end)
1173 Nodes::Between.new(self, left.and(right))
1174 end
1175 end
1176 def in other
1177 case other
1178 when Arel::SelectManager
1179 Arel::Nodes::In.new(self, other.ast)
1180 when Range
1181 if $VERBOSE
1182 warn -eowarn
1183 eowarn
1184 end
1185 between(other)
1186 when Enumerable
1187 Nodes::In.new self, quoted_array(other)
1188 else
1189 Nodes::In.new self, quoted_node(other)
1190 end
1191 end
1192 def in_any others
1193 grouping_any :in, others
1194 end
1195 def in_all others
1196 grouping_all :in, others
1197 end
1198 def not_between other
1199 if equals_quoted?(other.begin, -Float::INFINITY)
1200 if equals_quoted?(other.end, Float::INFINITY)
1201 self.in([])
1202 elsif other.exclude_end?
1203 gteq(other.end)
1204 else
1205 gt(other.end)
1206 end
1207 elsif equals_quoted?(other.end, Float::INFINITY)
1208 lt(other.begin)
1209 else
1210 left = lt(other.begin)
1211 right = if other.exclude_end?
1212 gteq(other.end)
1213 else
1214 gt(other.end)
1215 end
1216 left.or(right)
1217 end
1218 end
1219 def not_in other
1220 case other
1221 when Arel::SelectManager
1222 Arel::Nodes::NotIn.new(self, other.ast)
1223 when Range
1224 if $VERBOSE
1225 warn -eowarn
1226 eowarn
1227 end
1228 not_between(other)
1229 when Enumerable
1230 Nodes::NotIn.new self, quoted_array(other)
1231 else
1232 Nodes::NotIn.new self, quoted_node(other)
1233 end
1234 end
1235 def not_in_any others
1236 grouping_any :not_in, others
1237 end
1238 def not_in_all others
1239 grouping_all :not_in, others
1240 end
1241 def matches other, escape = nil
1242 end
1243 def matches_any others, escape = nil
1244 grouping_any :matches, others, escape
1245 end
1246 def matches_all others, escape = nil
1247 grouping_all :matches, others, escape
1248 end
1249 def does_not_match other, escape = nil
1250 end
1251 def does_not_match_any others, escape = nil
1252 grouping_any :does_not_match, others, escape
1253 end
1254 def does_not_match_all others, escape = nil
1255 grouping_all :does_not_match, others, escape
1256 end
1257 def gteq right
1258 end
1259 def gteq_any others
1260 grouping_any :gteq, others
1261 end
1262 def gteq_all others
1263 grouping_all :gteq, others
1264 end
1265 def gt right
1266 Nodes::GreaterThan.new self, quoted_node(right)
1267 end
1268 def gt_any others
1269 grouping_any :gt, others
1270 end
1271 def gt_all others
1272 grouping_all :gt, others
1273 end
1274 def lt right
1275 Nodes::LessThan.new self, quoted_node(right)
1276 end
1277 def lt_any others
1278 grouping_any :lt, others
1279 end
1280 def lt_all others
1281 grouping_all :lt, others
1282 end
1283 def lteq right
1284 end
1285 def lteq_any others
1286 grouping_any :lteq, others
1287 end
1288 def lteq_all others
1289 grouping_all :lteq, others
1290 end
1291 private
1292 def grouping_any method_id, others, *extras
1293 Nodes::Grouping.new nodes.inject { |memo,node|
1294 Nodes::Or.new(memo, node)
1295 }
1296 end
1297 def grouping_all method_id, others, *extras
1298 Nodes::Grouping.new Nodes::And.new(nodes)
1299 end
1300 def quoted_node(other)
1301 Nodes.build_quoted(other, self)
1302 end
1303 def quoted_array(others)
1304 others.map { |v| quoted_node(v) }
1305 end
1306 def equals_quoted?(maybe_quoted, value)
1307 if maybe_quoted.is_a?(Nodes::Quoted)
1308 maybe_quoted.val == value
1309 else
1310 maybe_quoted == value
1311 end
1312 end
1313 end
1314 end
1315 require 'arel/collectors/sql_string'
1316 module Arel
1317 class SelectManager Arel::TreeManager
1318 include Arel::Crud
1319 STRING_OR_SYMBOL_CLASS = [Symbol, String]
1320 def initialize table = nil
1321 super()
1322 @ast = Nodes::SelectStatement.new
1323 @ctx = @ast.cores.last
1324 from table
1325 end
1326 def initialize_copy other
1327 super
1328 @ctx = @ast.cores.last
1329 end
1330 def limit
1331 @ast.limit && @ast.limit.expr.expr
1332 end
1333 alias :taken :limit
1334 def constraints
1335 @ctx.wheres
1336 end
1337 def offset
1338 @ast.offset && @ast.offset.expr
1339 end
1340 def skip amount
1341 if amount
1342 @ast.offset = Nodes::Offset.new(amount)
1343 else
1344 @ast.offset = nil
1345 end
1346 self
1347 end
1348 alias :offset= :skip
1349 def exists
1350 Arel::Nodes::Exists.new @ast
1351 end
1352 def as other
1353 end
1354 def lock locking = Arel.sql('FOR UPDATE')
1355 case locking
1356 when true
1357 locking = Arel.sql('FOR UPDATE')
1358 when Arel::Nodes::SqlLiteral
1359 when String
1360 locking = Arel.sql locking
1361 end
1362 @ast.lock = Nodes::Lock.new(locking)
1363 self
1364 end
1365 def locked
1366 @ast.lock
1367 end
1368 def on *exprs
1369 self
1370 end
1371 def group *columns
1372 columns.each do |column|
1373 @ctx.groups.push Nodes::Group.new column
1374 end
1375 self
1376 end
1377 def from table
1378 case table
1379 when Nodes::Join
1380 @ctx.source.right table
1381 else
1382 @ctx.source.left = table
1383 end
1384 self
1385 end
1386 def froms
1387 @ast.cores.map { |x| x.from }.compact
1388 end
1389 def join relation, klass = Nodes::InnerJoin
1390 return self unless relation
1391 case relation
1392 when String, Nodes::SqlLiteral
1393 raise if relation.empty?
1394 klass = Nodes::StringJoin
1395 end
1396 self
1397 end
1398 def outer_join relation
1399 join(relation, Nodes::OuterJoin)
1400 end
1401 def having expr
1402 @ctx.havings expr
1403 self
1404 end
1405 def window name
1406 window = Nodes::NamedWindow.new(name)
1407 @ctx.windows.push window
1408 window
1409 end
1410 def project *projections
1411 @ctx.projections.concat projections.map { |x|
1412 }
1413 self
1414 end
1415 def projections
1416 @ctx.projections
1417 end
1418 def projections= projections
1419 @ctx.projections = projections
1420 end
1421 def distinct(value = true)
1422 if value
1423 @ctx.set_quantifier = Arel::Nodes::Distinct.new
1424 else
1425 @ctx.set_quantifier = nil
1426 end
1427 self
1428 end
1429 def distinct_on(value)
1430 if value
1431 else
1432 @ctx.set_quantifier = nil
1433 end
1434 self
1435 end
1436 def order *expr
1437 @ast.orders.concat expr.map { |x|
1438 }
1439 self
1440 end
1441 def orders
1442 @ast.orders
1443 end
1444 def where_sql engine = Table.engine
1445 return if @ctx.wheres.empty?
1446 viz = Visitors::WhereSql.new engine.connection
1447 end
1448 def union operation, other = nil
1449 if other
1450 else
1451 other = operation
1452 node_class = Nodes::Union
1453 end
1454 node_class.new self.ast, other.ast
1455 end
1456 def intersect other
1457 Nodes::Intersect.new ast, other.ast
1458 end
1459 def except other
1460 Nodes::Except.new ast, other.ast
1461 end
1462 alias :minus :except
1463 def with *subqueries
1464 if subqueries.first.is_a? Symbol
1465 else
1466 node_class = Nodes::With
1467 end
1468 @ast.with = node_class.new(subqueries.flatten)
1469 self
1470 end
1471 def take limit
1472 if limit
1473 else
1474 @ast.limit = nil
1475 @ctx.top = nil
1476 end
1477 self
1478 end
1479 alias limit= take
1480 def join_sources
1481 @ctx.source.right
1482 end
1483 def source
1484 @ctx.source
1485 end
1486 class Row Struct.new(:data) # :nodoc:
1487 def id
1488 data['id']
1489 end
1490 def method_missing(name, *args)
1491 name = name.to_s
1492 return data[name] if data.key?(name)
1493 super
1494 end
1495 end
1496 private
1497 def collapse exprs, existing = nil
1498 exprs = exprs.unshift(existing.expr) if existing
1499 exprs = exprs.compact.map { |expr|
1500 if String === expr
1501 Arel.sql(expr)
1502 else
1503 expr
1504 end
1505 }
1506 if exprs.length == 1
1507 exprs.first
1508 else
1509 create_and exprs
1510 end
1511 end
1512 end
1513 end
1514 module Arel
1515 class Table
1516 include Arel::Crud
1517 include Arel::FactoryMethods
1518 @engine = nil
1519 class self; attr_accessor :engine; end
1520 attr_accessor :name, :aliases, :table_alias
1521 alias :table_name :name
1522 def initialize(name, as: nil, type_caster: nil)
1523 @name = name.to_s
1524 @columns = nil
1525 @aliases = []
1526 @type_caster = type_caster
1527 if as.to_s == @name
1528 as = nil
1529 end
1530 @table_alias = as
1531 end
1532 def alias name = "#{self.name}_2"
1533 Nodes::TableAlias.new(self, name).tap do |node|
1534 @aliases node
1535 end
1536 end
1537 def from
1538 SelectManager.new(self)
1539 end
1540 def join relation, klass = Nodes::InnerJoin
1541 return from unless relation
1542 case relation
1543 when String, Nodes::SqlLiteral
1544 raise if relation.empty?
1545 klass = Nodes::StringJoin
1546 end
1547 from.join(relation, klass)
1548 end
1549 def outer_join relation
1550 join(relation, Nodes::OuterJoin)
1551 end
1552 def group *columns
1553 from.group(*columns)
1554 end
1555 def order *expr
1556 from.order(*expr)
1557 end
1558 def where condition
1559 from.where condition
1560 end
1561 def project *things
1562 from.project(*things)
1563 end
1564 def take amount
1565 from.take amount
1566 end
1567 def skip amount
1568 from.skip amount
1569 end
1570 def having expr
1571 from.having expr
1572 end
1573 def [] name
1574 ::Arel::Attribute.new self, name
1575 end
1576 def hash
1577 @name.hash
1578 end
1579 def eql? other
1580 self.class == other.class &&
1581 self.name == other.name &&
1582 self.aliases == other.aliases &&
1583 self.table_alias == other.table_alias
1584 end
1585 alias :== :eql?
1586 def type_cast_for_database(attribute_name, value)
1587 end
1588 def able_to_type_cast?
1589 !type_caster.nil?
1590 end
1591 protected
1592 attr_reader :type_caster
1593 private
1594 def attributes_for columns
1595 return nil unless columns
1596 columns.map do |column|
1597 end
1598 end
1599 end
1600 end
1601 require 'arel/collectors/sql_string'
1602 module Arel
1603 class TreeManager
1604 include Arel::FactoryMethods
1605 attr_reader :ast, :engine
1606 attr_accessor :bind_values
1607 def initialize
1608 @ctx = nil
1609 @bind_values = []
1610 end
1611 def to_dot
1612 collector = Arel::Collectors::PlainString.new
1613 collector.value
1614 end
1615 def to_sql engine = Table.engine
1616 collector = Arel::Collectors::SQLString.new
1617 collector.value
1618 end
1619 def initialize_copy other
1620 super
1621 @ast = @ast.clone
1622 end
1623 def where expr
1624 if Arel::TreeManager === expr
1625 expr = expr.ast
1626 end
1627 @ctx.wheres expr
1628 self
1629 end
1630 end
1631 end
1632 module Arel
1633 class UpdateManager Arel::TreeManager
1634 def initialize
1635 super
1636 @ast = Nodes::UpdateStatement.new
1637 @ctx = @ast
1638 end
1639 def take limit
1640 self
1641 end
1642 def key= key
1643 @ast.key = Nodes.build_quoted(key)
1644 end
1645 def key
1646 @ast.key
1647 end
1648 def order *expr
1649 @ast.orders = expr
1650 self
1651 end
1652 def table table
1653 @ast.relation = table
1654 self
1655 end
1656 def wheres= exprs
1657 @ast.wheres = exprs
1658 end
1659 def where expr
1660 @ast.wheres expr
1661 self
1662 end
1663 def set values
1664 if String === values
1665 @ast.values = [values]
1666 else
1667 @ast.values = values.map { |column,value|
1668 Nodes::Assignment.new(
1669 Nodes::UnqualifiedColumn.new(column),
1670 value
1671 )
1672 }
1673 end
1674 self
1675 end
1676 end
1677 end
1678 module Arel
1679 module Visitors
1680 class BindSubstitute
1681 def initialize delegate
1682 @delegate = delegate
1683 end
1684 end
1685 end
1686 end
1687 module Arel
1688 module Visitors
1689 module BindVisitor
1690 def initialize target
1691 @block = nil
1692 super
1693 end
1694 def accept node, collector, &block
1695 @block = block if block_given?
1696 super
1697 end
1698 private
1699 def visit_Arel_Nodes_Assignment o, collector
1700 if o.right.is_a? Arel::Nodes::BindParam
1701 collector = visit o.left, collector
1702 collector " = "
1703 visit o.right, collector
1704 else
1705 super
1706 end
1707 end
1708 def visit_Arel_Nodes_BindParam o, collector
1709 if @block
1710 val = @block.call
1711 if String === val
1712 collector val
1713 end
1714 else
1715 super
1716 end
1717 end
1718 end
1719 end
1720 end
1721 module Arel
1722 module Visitors
1723 class DepthFirst Arel::Visitors::Visitor
1724 def initialize block = nil
1725 @block = block || Proc.new
1726 super()
1727 end
1728 private
1729 def visit o
1730 super
1731 @block.call o
1732 end
1733 def unary o
1734 visit o.expr
1735 end
1736 alias :visit_Arel_Nodes_Group :unary
1737 alias :visit_Arel_Nodes_Grouping :unary
1738 alias :visit_Arel_Nodes_Having :unary
1739 alias :visit_Arel_Nodes_Limit :unary
1740 alias :visit_Arel_Nodes_Not :unary
1741 alias :visit_Arel_Nodes_Offset :unary
1742 alias :visit_Arel_Nodes_On :unary
1743 alias :visit_Arel_Nodes_Ordering :unary
1744 alias :visit_Arel_Nodes_Ascending :unary
1745 alias :visit_Arel_Nodes_Descending :unary
1746 alias :visit_Arel_Nodes_Top :unary
1747 alias :visit_Arel_Nodes_UnqualifiedColumn :unary
1748 def function o
1749 visit o.expressions
1750 visit o.alias
1751 visit o.distinct
1752 end
1753 alias :visit_Arel_Nodes_Avg :function
1754 alias :visit_Arel_Nodes_Exists :function
1755 alias :visit_Arel_Nodes_Max :function
1756 alias :visit_Arel_Nodes_Min :function
1757 alias :visit_Arel_Nodes_Sum :function
1758 def visit_Arel_Nodes_NamedFunction o
1759 visit o.name
1760 visit o.expressions
1761 visit o.distinct
1762 visit o.alias
1763 end
1764 def visit_Arel_Nodes_Count o
1765 visit o.expressions
1766 visit o.alias
1767 visit o.distinct
1768 end
1769 def nary o
1770 o.children.each { |child| visit child}
1771 end
1772 alias :visit_Arel_Nodes_And :nary
1773 def binary o
1774 visit o.left
1775 visit o.right
1776 end
1777 alias :visit_Arel_Nodes_As :binary
1778 alias :visit_Arel_Nodes_Assignment :binary
1779 alias :visit_Arel_Nodes_Between :binary
1780 alias :visit_Arel_Nodes_DeleteStatement :binary
1781 alias :visit_Arel_Nodes_DoesNotMatch :binary
1782 alias :visit_Arel_Nodes_Equality :binary
1783 alias :visit_Arel_Nodes_FullOuterJoin :binary
1784 alias :visit_Arel_Nodes_GreaterThan :binary
1785 alias :visit_Arel_Nodes_In :binary
1786 alias :visit_Arel_Nodes_InfixOperation :binary
1787 alias :visit_Arel_Nodes_JoinSource :binary
1788 alias :visit_Arel_Nodes_InnerJoin :binary
1789 alias :visit_Arel_Nodes_LessThan :binary
1790 alias :visit_Arel_Nodes_LessThanOrEqual :binary
1791 alias :visit_Arel_Nodes_Matches :binary
1792 alias :visit_Arel_Nodes_NotEqual :binary
1793 alias :visit_Arel_Nodes_NotIn :binary
1794 alias :visit_Arel_Nodes_NotRegexp :binary
1795 alias :visit_Arel_Nodes_Or :binary
1796 alias :visit_Arel_Nodes_OuterJoin :binary
1797 alias :visit_Arel_Nodes_Regexp :binary
1798 alias :visit_Arel_Nodes_RightOuterJoin :binary
1799 alias :visit_Arel_Nodes_TableAlias :binary
1800 alias :visit_Arel_Nodes_Values :binary
1801 alias :visit_Arel_Nodes_Union :binary
1802 def visit_Arel_Nodes_StringJoin o
1803 visit o.left
1804 end
1805 def visit_Arel_Attribute o
1806 visit o.relation
1807 visit o.name
1808 end
1809 def visit_Arel_Table o
1810 visit o.name
1811 end
1812 def terminal o
1813 end
1814 alias :visit_Arel_Nodes_Lock :terminal
1815 alias :visit_Arel_Nodes_Node :terminal
1816 alias :visit_Arel_Nodes_SqlLiteral :terminal
1817 alias :visit_Arel_Nodes_BindParam :terminal
1818 alias :visit_Arel_Nodes_Window :terminal
1819 alias :visit_Arel_Nodes_True :terminal
1820 alias :visit_Arel_Nodes_False :terminal
1821 alias :visit_BigDecimal :terminal
1822 alias :visit_Bignum :terminal
1823 alias :visit_Class :terminal
1824 alias :visit_Date :terminal
1825 alias :visit_DateTime :terminal
1826 alias :visit_FalseClass :terminal
1827 alias :visit_Fixnum :terminal
1828 alias :visit_Float :terminal
1829 alias :visit_NilClass :terminal
1830 alias :visit_String :terminal
1831 alias :visit_Symbol :terminal
1832 alias :visit_Time :terminal
1833 alias :visit_TrueClass :terminal
1834 def visit_Arel_Nodes_InsertStatement o
1835 visit o.relation
1836 visit o.columns
1837 visit o.values
1838 end
1839 def visit_Arel_Nodes_SelectCore o
1840 visit o.projections
1841 visit o.source
1842 visit o.wheres
1843 visit o.groups
1844 visit o.windows
1845 visit o.havings
1846 end
1847 def visit_Arel_Nodes_SelectStatement o
1848 visit o.cores
1849 visit o.orders
1850 visit o.limit
1851 visit o.lock
1852 visit o.offset
1853 end
1854 def visit_Arel_Nodes_UpdateStatement o
1855 visit o.relation
1856 visit o.values
1857 visit o.wheres
1858 visit o.orders
1859 visit o.limit
1860 end
1861 def visit_Array o
1862 o.each { |i| visit i }
1863 end
1864 alias :visit_Set :visit_Array
1865 def visit_Hash o
1866 o.each { |k,v| visit(k); visit(v) }
1867 end
1868 DISPATCH = dispatch_cache
1869 def get_dispatch_cache
1870 DISPATCH
1871 end
1872 end
1873 end
1874 end
1875 module Arel
1876 module Visitors
1877 class Dot Arel::Visitors::Visitor
1878 class Node # :nodoc:
1879 attr_accessor :name, :id, :fields
1880 def initialize name, id, fields = []
1881 @name = name
1882 @id = id
1883 @fields = fields
1884 end
1885 end
1886 class Edge Struct.new :name, :from, :to # :nodoc:
1887 end
1888 def initialize
1889 super()
1890 @nodes = []
1891 @edges = []
1892 @node_stack = []
1893 @edge_stack = []
1894 @seen = {}
1895 end
1896 def accept object, collector
1897 visit object
1898 collector to_dot
1899 end
1900 private
1901 def visit_Arel_Nodes_Ordering o
1902 visit_edge o, "expr"
1903 end
1904 def visit_Arel_Nodes_TableAlias o
1905 visit_edge o, "name"
1906 visit_edge o, "relation"
1907 end
1908 def visit_Arel_Nodes_Count o
1909 visit_edge o, "expressions"
1910 visit_edge o, "distinct"
1911 end
1912 def visit_Arel_Nodes_Values o
1913 visit_edge o, "expressions"
1914 end
1915 def visit_Arel_Nodes_StringJoin o
1916 visit_edge o, "left"
1917 end
1918 def visit_Arel_Nodes_InnerJoin o
1919 visit_edge o, "left"
1920 visit_edge o, "right"
1921 end
1922 def visit_Arel_Nodes_DeleteStatement o
1923 visit_edge o, "relation"
1924 visit_edge o, "wheres"
1925 end
1926 def unary o
1927 visit_edge o, "expr"
1928 end
1929 alias :visit_Arel_Nodes_Group :unary
1930 alias :visit_Arel_Nodes_Grouping :unary
1931 alias :visit_Arel_Nodes_Having :unary
1932 alias :visit_Arel_Nodes_Limit :unary
1933 alias :visit_Arel_Nodes_Not :unary
1934 alias :visit_Arel_Nodes_Offset :unary
1935 alias :visit_Arel_Nodes_On :unary
1936 alias :visit_Arel_Nodes_Top :unary
1937 alias :visit_Arel_Nodes_UnqualifiedColumn :unary
1938 alias :visit_Arel_Nodes_Preceding :unary
1939 alias :visit_Arel_Nodes_Following :unary
1940 alias :visit_Arel_Nodes_Rows :unary
1941 alias :visit_Arel_Nodes_Range :unary
1942 def window o
1943 visit_edge o, "partitions"
1944 visit_edge o, "orders"
1945 visit_edge o, "framing"
1946 end
1947 alias :visit_Arel_Nodes_Window :window
1948 def named_window o
1949 visit_edge o, "partitions"
1950 visit_edge o, "orders"
1951 visit_edge o, "framing"
1952 visit_edge o, "name"
1953 end
1954 alias :visit_Arel_Nodes_NamedWindow :named_window
1955 def function o
1956 visit_edge o, "expressions"
1957 visit_edge o, "distinct"
1958 visit_edge o, "alias"
1959 end
1960 alias :visit_Arel_Nodes_Exists :function
1961 alias :visit_Arel_Nodes_Min :function
1962 alias :visit_Arel_Nodes_Max :function
1963 alias :visit_Arel_Nodes_Avg :function
1964 alias :visit_Arel_Nodes_Sum :function
1965 def extract o
1966 visit_edge o, "expressions"
1967 visit_edge o, "alias"
1968 end
1969 alias :visit_Arel_Nodes_Extract :extract
1970 def visit_Arel_Nodes_NamedFunction o
1971 visit_edge o, "name"
1972 visit_edge o, "expressions"
1973 visit_edge o, "distinct"
1974 visit_edge o, "alias"
1975 end
1976 def visit_Arel_Nodes_InsertStatement o
1977 visit_edge o, "relation"
1978 visit_edge o, "columns"
1979 visit_edge o, "values"
1980 end
1981 def visit_Arel_Nodes_SelectCore o
1982 visit_edge o, "source"
1983 visit_edge o, "projections"
1984 visit_edge o, "wheres"
1985 visit_edge o, "windows"
1986 end
1987 def visit_Arel_Nodes_SelectStatement o
1988 visit_edge o, "cores"
1989 visit_edge o, "limit"
1990 visit_edge o, "orders"
1991 visit_edge o, "offset"
1992 end
1993 def visit_Arel_Nodes_UpdateStatement o
1994 visit_edge o, "relation"
1995 visit_edge o, "wheres"
1996 visit_edge o, "values"
1997 end
1998 def visit_Arel_Table o
1999 visit_edge o, "name"
2000 end
2001 def visit_Arel_Attribute o
2002 visit_edge o, "relation"
2003 visit_edge o, "name"
2004 end
2005 def nary o
2006 o.children.each_with_index do |x,i|
2007 edge(i) { visit x }
2008 end
2009 end
2010 alias :visit_Arel_Nodes_And :nary
2011 def binary o
2012 visit_edge o, "left"
2013 visit_edge o, "right"
2014 end
2015 alias :visit_Arel_Nodes_As :binary
2016 alias :visit_Arel_Nodes_Assignment :binary
2017 alias :visit_Arel_Nodes_Between :binary
2018 alias :visit_Arel_Nodes_DoesNotMatch :binary
2019 alias :visit_Arel_Nodes_Equality :binary
2020 alias :visit_Arel_Nodes_GreaterThan :binary
2021 alias :visit_Arel_Nodes_In :binary
2022 alias :visit_Arel_Nodes_JoinSource :binary
2023 alias :visit_Arel_Nodes_LessThan :binary
2024 alias :visit_Arel_Nodes_LessThanOrEqual :binary
2025 alias :visit_Arel_Nodes_Matches :binary
2026 alias :visit_Arel_Nodes_NotEqual :binary
2027 alias :visit_Arel_Nodes_NotIn :binary
2028 alias :visit_Arel_Nodes_Or :binary
2029 alias :visit_Arel_Nodes_Over :binary
2030 def visit_String o
2031 @node_stack.last.fields o
2032 end
2033 alias :visit_Time :visit_String
2034 alias :visit_Date :visit_String
2035 alias :visit_DateTime :visit_String
2036 alias :visit_NilClass :visit_String
2037 alias :visit_TrueClass :visit_String
2038 alias :visit_FalseClass :visit_String
2039 alias :visit_Arel_Nodes_BindParam :visit_String
2040 alias :visit_Fixnum :visit_String
2041 alias :visit_BigDecimal :visit_String
2042 alias :visit_Float :visit_String
2043 alias :visit_Symbol :visit_String
2044 alias :visit_Arel_Nodes_SqlLiteral :visit_String
2045 def visit_Hash o
2046 o.each_with_index do |pair, i|
2047 edge("pair_#{i}") { visit pair }
2048 end
2049 end
2050 def visit_Array o
2051 o.each_with_index do |x,i|
2052 edge(i) { visit x }
2053 end
2054 end
2055 alias :visit_Set :visit_Array
2056 def visit_edge o, method
2057 edge(method) { visit o.send(method) }
2058 end
2059 def visit o
2060 if node = @seen[o.object_id]
2061 @edge_stack.last.to = node
2062 return
2063 end
2064 node = Node.new(o.class.name, o.object_id)
2065 @seen[node.id] = node
2066 @nodes node
2067 with_node node do
2068 super
2069 end
2070 end
2071 def edge name
2072 edge = Edge.new(name, @node_stack.last)
2073 @edge_stack.push edge
2074 @edges edge
2075 yield
2076 @edge_stack.pop
2077 end
2078 def with_node node
2079 if edge = @edge_stack.last
2080 edge.to = node
2081 end
2082 @node_stack.push node
2083 yield
2084 @node_stack.pop
2085 end
2086 def quote string
2087 string.to_s.gsub('"', '\"')
2088 end
2089 def to_dot
2090 @nodes.map { |node|
2091 label = "f0#{node.name}"
2092 node.fields.each_with_index do |field, i|
2093 label "|f#{i + 1}#{quote field}"
2094 end
2095 "#{node.id} [label=\"#{label}\"];"
2096 }.join("
") + "
" + @edges.map { |edge|
2097 }.join("
") + "
}"
2098 end
2099 end
2100 end
2101 end
2102 module Arel
2103 module Visitors
2104 class IBM_DB Arel::Visitors::ToSql
2105 private
2106 def visit_Arel_Nodes_Limit o, collector
2107 collector "FETCH FIRST "
2108 collector = visit o.expr, collector
2109 collector " ROWS ONLY"
2110 end
2111 end
2112 end
2113 end
2114 module Arel
2115 module Visitors
2116 class Informix Arel::Visitors::ToSql
2117 private
2118 def visit_Arel_Nodes_SelectStatement o, collector
2119 collector "SELECT "
2120 collector = maybe_visit o.offset, collector
2121 collector = maybe_visit o.limit, collector
2122 collector = o.cores.inject(collector) { |c,x|
2123 visit_Arel_Nodes_SelectCore x, c
2124 }
2125 if o.orders.any?
2126 collector "ORDER BY "
2127 collector = inject_join o.orders, collector, ", "
2128 end
2129 collector = maybe_visit o.lock, collector
2130 end
2131 def visit_Arel_Nodes_SelectCore o, collector
2132 froms = false
2133 if o.source && !o.source.empty?
2134 froms = true
2135 collector " FROM "
2136 collector = visit o.source, collector
2137 end
2138 if o.wheres.any?
2139 collector " WHERE "
2140 end
2141 if o.groups.any?
2142 collector "GROUP BY "
2143 collector = inject_join o.groups, collector, ", "
2144 end
2145 if o.havings.any?
2146 collector " HAVING "
2147 end
2148 collector
2149 end
2150 def visit_Arel_Nodes_Offset o, collector
2151 collector "SKIP "
2152 visit o.expr, collector
2153 end
2154 def visit_Arel_Nodes_Limit o, collector
2155 collector "FIRST "
2156 visit o.expr, collector
2157 collector " "
2158 end
2159 end
2160 end
2161 end
2162 module Arel
2163 module Visitors
2164 class MSSQL Arel::Visitors::ToSql
2165 RowNumber = Struct.new :children
2166 def initialize(*)
2167 @primary_keys = {}
2168 super
2169 end
2170 private
2171 def visit_Arel_Nodes_Top o
2172 ""
2173 end
2174 collector "ROW_NUMBER() OVER (ORDER BY "
2175 end
2176 def visit_Arel_Nodes_SelectStatement o, collector
2177 if !o.limit && !o.offset
2178 return super
2179 end
2180 is_select_count = false
2181 o.cores.each { |x|
2182 if select_count? x
2183 x.projections = [core_order_by]
2184 is_select_count = true
2185 else
2186 x.projections core_order_by
2187 end
2188 }
2189 if is_select_count
2190 collector "SELECT COUNT(1) as count_id FROM ("
2191 end
2192 collector "SELECT _t.* FROM ("
2193 collector = o.cores.inject(collector) { |c,x|
2194 visit_Arel_Nodes_SelectCore x, c
2195 }
2196 if is_select_count
2197 collector ") AS subquery"
2198 else
2199 collector
2200 end
2201 end
2202 def get_offset_limit_clause o
2203 first_row = o.offset ? o.offset.expr.to_i + 1 : 1
2204 if last_row
2205 " _row_num BETWEEN #{first_row} AND #{last_row}"
2206 else
2207 " _row_num = #{first_row}"
2208 end
2209 end
2210 def determine_order_by orders, x
2211 if orders.any?
2212 orders
2213 elsif x.groups.any?
2214 x.groups
2215 else
2216 pk = find_left_table_pk(x.froms)
2217 pk ? [pk] : []
2218 end
2219 end
2220 def row_num_literal order_by
2221 RowNumber.new order_by
2222 end
2223 def select_count? x
2224 end
2225 def find_left_table_pk o
2226 if o.kind_of?(Arel::Nodes::Join)
2227 find_left_table_pk(o.left)
2228 elsif o.instance_of?(Arel::Table)
2229 find_primary_key(o)
2230 end
2231 end
2232 def find_primary_key(o)
2233 @primary_keys[o.name] ||= begin
2234 primary_key_name && o[primary_key_name]
2235 end
2236 end
2237 end
2238 end
2239 end
2240 module Arel
2241 module Visitors
2242 class MySQL Arel::Visitors::ToSql
2243 private
2244 unless suppress_parens
2245 collector "( "
2246 end
2247 collector = case o.left
2248 when Arel::Nodes::Union
2249 visit_Arel_Nodes_Union o.left, collector, true
2250 else
2251 visit o.left, collector
2252 end
2253 collector " UNION "
2254 collector = case o.right
2255 when Arel::Nodes::Union
2256 visit_Arel_Nodes_Union o.right, collector, true
2257 else
2258 visit o.right, collector
2259 end
2260 if suppress_parens
2261 collector
2262 else
2263 collector " )"
2264 end
2265 end
2266 def visit_Arel_Nodes_Bin o, collector
2267 collector "BINARY "
2268 visit o.expr, collector
2269 end
2270 def visit_Arel_Nodes_SelectStatement o, collector
2271 if o.offset && !o.limit
2272 end
2273 super
2274 end
2275 def visit_Arel_Nodes_SelectCore o, collector
2276 o.froms ||= Arel.sql('DUAL')
2277 super
2278 end
2279 def visit_Arel_Nodes_UpdateStatement o, collector
2280 collector "UPDATE "
2281 collector = visit o.relation, collector
2282 unless o.values.empty?
2283 collector " SET "
2284 collector = inject_join o.values, collector, ', '
2285 end
2286 unless o.wheres.empty?
2287 collector " WHERE "
2288 end
2289 unless o.orders.empty?
2290 collector " ORDER BY "
2291 collector = inject_join o.orders, collector, ', '
2292 end
2293 maybe_visit o.limit, collector
2294 end
2295 end
2296 end
2297 end
2298 module Arel
2299 module Visitors
2300 class Oracle Arel::Visitors::ToSql
2301 private
2302 def visit_Arel_Nodes_SelectStatement o, collector
2303 o = order_hacks(o)
2304 Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr
2305 )
2306 return super
2307 end
2308 if o.limit && o.offset
2309 o = o.dup
2310 limit = o.limit.expr.expr
2311 offset = o.offset
2312 o.offset = nil
2313 collector "
2314 SELECT * FROM (
2315 SELECT raw_sql_.*, rownum raw_rnum_
2316 FROM ("
2317 collector = super(o, collector)
2318 collector ") raw_sql_
2319 WHERE rownum = #{offset.expr.to_i + limit}
2320 )
2321 WHERE "
2322 return visit(offset, collector)
2323 end
2324 if o.limit
2325 o = o.dup
2326 limit = o.limit.expr
2327 collector "SELECT * FROM ("
2328 collector = super(o, collector)
2329 collector ") WHERE ROWNUM = "
2330 return visit limit, collector
2331 end
2332 if o.offset
2333 o = o.dup
2334 offset = o.offset
2335 o.offset = nil
2336 collector "SELECT * FROM (
2337 SELECT raw_sql_.*, rownum raw_rnum_
2338 FROM ("
2339 collector = super(o, collector)
2340 collector ") raw_sql_
2341 )
2342 WHERE "
2343 return visit offset, collector
2344 end
2345 super
2346 end
2347 def visit_Arel_Nodes_Limit o, collector
2348 collector
2349 end
2350 def visit_Arel_Nodes_Offset o, collector
2351 collector "raw_rnum_ "
2352 visit o.expr, collector
2353 end
2354 def visit_Arel_Nodes_Except o, collector
2355 collector "( "
2356 collector = infix_value o, collector, " MINUS "
2357 collector " )"
2358 end
2359 def visit_Arel_Nodes_UpdateStatement o, collector
2360 if o.orders.any? && o.limit.nil?
2361 o = o.dup
2362 o.orders = []
2363 end
2364 super
2365 end
2366 def order_hacks o
2367 return o if o.orders.empty?
2368 return o unless o.cores.any? do |core|
2369 core.projections.any? do |projection|
2370 /FIRST_VALUE/ === projection
2371 end
2372 end
2373 orders = o.orders.map do |x|
2374 if string.include?(',')
2375 split_order_string(string)
2376 else
2377 string
2378 end
2379 end.flatten
2380 o.orders = []
2381 orders.each_with_index do |order, i|
2382 o.orders
2383 end
2384 o
2385 end
2386 def split_order_string(string)
2387 array = []
2388 i = 0
2389 string.split(',').each do |part|
2390 if array[i]
2391 array[i] ',' part
2392 else
2393 array[i] = '' part
2394 end
2395 end
2396 array
2397 end
2398 def visit_Arel_Nodes_BindParam o, collector
2399 collector.add_bind(o) { |i| ":a#{i}" }
2400 end
2401 end
2402 end
2403 end
2404 module Arel
2405 module Visitors
2406 class PostgreSQL Arel::Visitors::ToSql
2407 private
2408 def visit_Arel_Nodes_Matches o, collector
2409 collector = infix_value o, collector, ' ILIKE '
2410 if o.escape
2411 collector ' ESCAPE '
2412 visit o.escape, collector
2413 else
2414 collector
2415 end
2416 end
2417 def visit_Arel_Nodes_DoesNotMatch o, collector
2418 if o.escape
2419 collector ' ESCAPE '
2420 visit o.escape, collector
2421 else
2422 collector
2423 end
2424 end
2425 def visit_Arel_Nodes_Regexp o, collector
2426 infix_value o, collector, ' ~ '
2427 end
2428 def visit_Arel_Nodes_NotRegexp o, collector
2429 infix_value o, collector, ' !~ '
2430 end
2431 def visit_Arel_Nodes_DistinctOn o, collector
2432 collector "DISTINCT ON ( "
2433 visit(o.expr, collector) " )"
2434 end
2435 def visit_Arel_Nodes_BindParam o, collector
2436 collector.add_bind(o) { |i| "$#{i}" }
2437 end
2438 end
2439 end
2440 end
2441 require 'arel/visitors/visitor'
2442 module Arel
2443 module Visitors
2444 class Reduce Arel::Visitors::Visitor
2445 def accept object, collector
2446 visit object, collector
2447 end
2448 private
2449 def visit object, collector
2450 send dispatch[object.class], object, collector
2451 rescue NoMethodError = e
2452 respond_to?(dispatch[klass], true)
2453 }
2454 dispatch[object.class] = dispatch[superklass]
2455 retry
2456 end
2457 end
2458 end
2459 end
2460 module Arel
2461 module Visitors
2462 class SQLite Arel::Visitors::ToSql
2463 private
2464 def visit_Arel_Nodes_Lock o, collector
2465 collector
2466 end
2467 def visit_Arel_Nodes_SelectStatement o, collector
2468 super
2469 end
2470 end
2471 end
2472 end
2473 require 'bigdecimal'
2474 require 'date'
2475 require 'arel/visitors/reduce'
2476 module Arel
2477 module Visitors
2478 class ToSql Arel::Visitors::Reduce
2479 WHERE = ' WHERE ' # :nodoc:
2480 SPACE = ' ' # :nodoc:
2481 COMMA = ', ' # :nodoc:
2482 GROUP_BY = ' GROUP BY ' # :nodoc:
2483 ORDER_BY = ' ORDER BY ' # :nodoc:
2484 WINDOW = ' WINDOW ' # :nodoc:
2485 AND = ' AND ' # :nodoc:
2486 DISTINCT = 'DISTINCT' # :nodoc:
2487 def initialize connection
2488 super()
2489 @connection = connection
2490 end
2491 def compile node, &block
2492 end
2493 private
2494 def schema_cache
2495 @connection.schema_cache
2496 end
2497 def visit_Arel_Nodes_DeleteStatement o, collector
2498 collector "DELETE FROM "
2499 collector = visit o.relation, collector
2500 if o.wheres.any?
2501 collector " WHERE "
2502 inject_join o.wheres, collector, AND
2503 else
2504 collector
2505 end
2506 end
2507 def build_subselect key, o
2508 stmt = Nodes::SelectStatement.new
2509 core = stmt.cores.first
2510 core.froms = o.relation
2511 core.wheres = o.wheres
2512 core.projections = [key]
2513 stmt.limit = o.limit
2514 stmt.orders = o.orders
2515 stmt
2516 end
2517 def visit_Arel_Nodes_UpdateStatement o, collector
2518 if o.orders.empty? && o.limit.nil?
2519 wheres = o.wheres
2520 else
2521 end
2522 collector "UPDATE "
2523 collector = visit o.relation, collector
2524 unless o.values.empty?
2525 collector " SET "
2526 collector = inject_join o.values, collector, ", "
2527 end
2528 unless wheres.empty?
2529 collector " WHERE "
2530 end
2531 collector
2532 end
2533 def visit_Arel_Nodes_InsertStatement o, collector
2534 collector "INSERT INTO "
2535 collector = visit o.relation, collector
2536 if o.columns.any?
2537 collector " (#{o.columns.map { |x|
2538 quote_column_name x.name
2539 }.join ', '})"
2540 end
2541 if o.values
2542 maybe_visit o.values, collector
2543 elsif o.select
2544 maybe_visit o.select, collector
2545 else
2546 collector
2547 end
2548 end
2549 def visit_Arel_Nodes_Exists o, collector
2550 collector "EXISTS ("
2551 collector = visit(o.expressions, collector) ")"
2552 if o.alias
2553 collector " AS "
2554 visit o.alias, collector
2555 else
2556 collector
2557 end
2558 end
2559 def visit_Arel_Nodes_Casted o, collector
2560 collector quoted(o.val, o.attribute).to_s
2561 end
2562 def visit_Arel_Nodes_Quoted o, collector
2563 collector quoted(o.expr, nil).to_s
2564 end
2565 def visit_Arel_Nodes_True o, collector
2566 collector "TRUE"
2567 end
2568 def visit_Arel_Nodes_False o, collector
2569 collector "FALSE"
2570 end
2571 def table_exists? name
2572 schema_cache.table_exists? name
2573 end
2574 def column_for attr
2575 return unless attr
2576 name = attr.name.to_s
2577 table = attr.relation.table_name
2578 return nil unless table_exists? table
2579 column_cache(table)[name]
2580 end
2581 def column_cache(table)
2582 schema_cache.columns_hash(table)
2583 end
2584 def visit_Arel_Nodes_Values o, collector
2585 collector "VALUES ("
2586 len = o.expressions.length - 1
2587 case value
2588 when Nodes::SqlLiteral, Nodes::BindParam
2589 collector = visit value, collector
2590 else
2591 end
2592 unless i == len
2593 collector ', '
2594 end
2595 }
2596 collector ")"
2597 end
2598 def visit_Arel_Nodes_SelectStatement o, collector
2599 if o.with
2600 collector = visit o.with, collector
2601 collector SPACE
2602 end
2603 collector = o.cores.inject(collector) { |c,x|
2604 visit_Arel_Nodes_SelectCore(x, c)
2605 }
2606 unless o.orders.empty?
2607 collector ORDER_BY
2608 len = o.orders.length - 1
2609 o.orders.each_with_index { |x, i|
2610 collector = visit(x, collector)
2611 collector COMMA unless len == i
2612 }
2613 end
2614 collector = maybe_visit o.limit, collector
2615 collector = maybe_visit o.offset, collector
2616 collector = maybe_visit o.lock, collector
2617 collector
2618 end
2619 def visit_Arel_Nodes_SelectCore o, collector
2620 collector "SELECT"
2621 collector = maybe_visit o.top, collector
2622 unless o.projections.empty?
2623 collector SPACE
2624 len = o.projections.length - 1
2625 o.projections.each_with_index do |x, i|
2626 collector = visit(x, collector)
2627 collector COMMA unless len == i
2628 end
2629 end
2630 if o.source && !o.source.empty?
2631 collector " FROM "
2632 collector = visit o.source, collector
2633 end
2634 unless o.wheres.empty?
2635 collector WHERE
2636 len = o.wheres.length - 1
2637 o.wheres.each_with_index do |x, i|
2638 collector = visit(x, collector)
2639 collector AND unless len == i
2640 end
2641 end
2642 unless o.groups.empty?
2643 collector GROUP_BY
2644 len = o.groups.length - 1
2645 o.groups.each_with_index do |x, i|
2646 collector = visit(x, collector)
2647 collector COMMA unless len == i
2648 end
2649 end
2650 unless o.havings.empty?
2651 collector " HAVING "
2652 inject_join o.havings, collector, AND
2653 end
2654 unless o.windows.empty?
2655 collector WINDOW
2656 len = o.windows.length - 1
2657 o.windows.each_with_index do |x, i|
2658 collector = visit(x, collector)
2659 collector COMMA unless len == i
2660 end
2661 end
2662 collector
2663 end
2664 def visit_Arel_Nodes_Bin o, collector
2665 visit o.expr, collector
2666 end
2667 def visit_Arel_Nodes_Distinct o, collector
2668 collector DISTINCT
2669 end
2670 def visit_Arel_Nodes_DistinctOn o, collector
2671 end
2672 def visit_Arel_Nodes_With o, collector
2673 collector "WITH "
2674 inject_join o.children, collector, ', '
2675 end
2676 def visit_Arel_Nodes_WithRecursive o, collector
2677 collector "WITH RECURSIVE "
2678 inject_join o.children, collector, ', '
2679 end
2680 def visit_Arel_Nodes_Union o, collector
2681 collector "( "
2682 infix_value(o, collector, " UNION ") " )"
2683 end
2684 def visit_Arel_Nodes_UnionAll o, collector
2685 collector "( "
2686 infix_value(o, collector, " UNION ALL ") " )"
2687 end
2688 def visit_Arel_Nodes_Intersect o, collector
2689 collector "( "
2690 infix_value(o, collector, " INTERSECT ") " )"
2691 end
2692 def visit_Arel_Nodes_Except o, collector
2693 collector "( "
2694 infix_value(o, collector, " EXCEPT ") " )"
2695 end
2696 def visit_Arel_Nodes_NamedWindow o, collector
2697 collector quote_column_name(o.name)
2698 collector " AS "
2699 visit_Arel_Nodes_Window o, collector
2700 end
2701 def visit_Arel_Nodes_Window o, collector
2702 collector "("
2703 if o.partitions.any?
2704 collector "PARTITION BY "
2705 end
2706 if o.orders.any?
2707 collector ' ' if o.partitions.any?
2708 collector "ORDER BY "
2709 collector = inject_join o.orders, collector, ", "
2710 end
2711 if o.framing
2712 collector = visit o.framing, collector
2713 end
2714 collector ")"
2715 end
2716 def visit_Arel_Nodes_Rows o, collector
2717 if o.expr
2718 collector "ROWS "
2719 visit o.expr, collector
2720 else
2721 collector "ROWS"
2722 end
2723 end
2724 def visit_Arel_Nodes_Range o, collector
2725 if o.expr
2726 collector "RANGE "
2727 visit o.expr, collector
2728 else
2729 collector "RANGE"
2730 end
2731 end
2732 def visit_Arel_Nodes_Preceding o, collector
2733 collector = if o.expr
2734 visit o.expr, collector
2735 else
2736 collector "UNBOUNDED"
2737 end
2738 collector " PRECEDING"
2739 end
2740 def visit_Arel_Nodes_Following o, collector
2741 collector = if o.expr
2742 visit o.expr, collector
2743 else
2744 collector "UNBOUNDED"
2745 end
2746 collector " FOLLOWING"
2747 end
2748 def visit_Arel_Nodes_CurrentRow o, collector
2749 collector "CURRENT ROW"
2750 end
2751 def visit_Arel_Nodes_Over o, collector
2752 case o.right
2753 when nil
2754 visit(o.left, collector) " OVER ()"
2755 when Arel::Nodes::SqlLiteral
2756 infix_value o, collector, " OVER "
2757 when String, Symbol
2758 else
2759 infix_value o, collector, " OVER "
2760 end
2761 end
2762 def visit_Arel_Nodes_Offset o, collector
2763 collector "OFFSET "
2764 visit o.expr, collector
2765 end
2766 def visit_Arel_Nodes_Limit o, collector
2767 collector "LIMIT "
2768 visit o.expr, collector
2769 end
2770 def visit_Arel_Nodes_Top o, collector
2771 collector
2772 end
2773 def visit_Arel_Nodes_Lock o, collector
2774 visit o.expr, collector
2775 end
2776 def visit_Arel_Nodes_Grouping o, collector
2777 if o.expr.is_a? Nodes::Grouping
2778 visit(o.expr, collector)
2779 else
2780 collector "("
2781 visit(o.expr, collector) ")"
2782 end
2783 end
2784 def visit_Arel_SelectManager o, collector
2785 collector "(#{o.to_sql.rstrip})"
2786 end
2787 def visit_Arel_Nodes_Ascending o, collector
2788 visit(o.expr, collector) " ASC"
2789 end
2790 def visit_Arel_Nodes_Descending o, collector
2791 visit(o.expr, collector) " DESC"
2792 end
2793 def visit_Arel_Nodes_Group o, collector
2794 visit o.expr, collector
2795 end
2796 def visit_Arel_Nodes_NamedFunction o, collector
2797 collector o.name
2798 collector "("
2799 collector "DISTINCT " if o.distinct
2800 if o.alias
2801 collector " AS "
2802 visit o.alias, collector
2803 else
2804 collector
2805 end
2806 end
2807 def visit_Arel_Nodes_Extract o, collector
2808 collector "EXTRACT(#{o.field.to_s.upcase} FROM "
2809 visit(o.expr, collector) ")"
2810 end
2811 def visit_Arel_Nodes_Count o, collector
2812 aggregate "COUNT", o, collector
2813 end
2814 def visit_Arel_Nodes_Sum o, collector
2815 aggregate "SUM", o, collector
2816 end
2817 def visit_Arel_Nodes_Max o, collector
2818 aggregate "MAX", o, collector
2819 end
2820 def visit_Arel_Nodes_Min o, collector
2821 aggregate "MIN", o, collector
2822 end
2823 def visit_Arel_Nodes_Avg o, collector
2824 aggregate "AVG", o, collector
2825 end
2826 def visit_Arel_Nodes_TableAlias o, collector
2827 collector = visit o.relation, collector
2828 collector " "
2829 collector quote_table_name(o.name)
2830 end
2831 def visit_Arel_Nodes_Between o, collector
2832 collector = visit o.left, collector
2833 collector " BETWEEN "
2834 visit o.right, collector
2835 end
2836 collector = visit o.left, collector
2837 collector " = "
2838 visit o.right, collector
2839 end
2840 def visit_Arel_Nodes_GreaterThan o, collector
2841 collector = visit o.left, collector
2842 collector " "
2843 visit o.right, collector
2844 end
2845 def visit_Arel_Nodes_LessThanOrEqual o, collector
2846 collector = visit o.left, collector
2847 collector " = "
2848 visit o.right, collector
2849 end
2850 def visit_Arel_Nodes_LessThan o, collector
2851 collector = visit o.left, collector
2852 collector " "
2853 visit o.right, collector
2854 end
2855 def visit_Arel_Nodes_Matches o, collector
2856 collector = visit o.left, collector
2857 collector " LIKE "
2858 collector = visit o.right, collector
2859 if o.escape
2860 collector ' ESCAPE '
2861 visit o.escape, collector
2862 else
2863 collector
2864 end
2865 end
2866 def visit_Arel_Nodes_DoesNotMatch o, collector
2867 collector = visit o.left, collector
2868 collector " NOT LIKE "
2869 collector = visit o.right, collector
2870 if o.escape
2871 collector ' ESCAPE '
2872 visit o.escape, collector
2873 else
2874 collector
2875 end
2876 end
2877 def visit_Arel_Nodes_JoinSource o, collector
2878 if o.left
2879 collector = visit o.left, collector
2880 end
2881 if o.right.any?
2882 collector " " if o.left
2883 collector = inject_join o.right, collector, ' '
2884 end
2885 collector
2886 end
2887 def visit_Arel_Nodes_Regexp o, collector
2888 end
2889 def visit_Arel_Nodes_NotRegexp o, collector
2890 end
2891 def visit_Arel_Nodes_StringJoin o, collector
2892 visit o.left, collector
2893 end
2894 def visit_Arel_Nodes_FullOuterJoin o
2895 end
2896 def visit_Arel_Nodes_OuterJoin o, collector
2897 collector "LEFT OUTER JOIN "
2898 collector = visit o.left, collector
2899 collector " "
2900 visit o.right, collector
2901 end
2902 def visit_Arel_Nodes_RightOuterJoin o
2903 end
2904 def visit_Arel_Nodes_InnerJoin o, collector
2905 collector "INNER JOIN "
2906 collector = visit o.left, collector
2907 if o.right
2908 collector SPACE
2909 visit(o.right, collector)
2910 else
2911 collector
2912 end
2913 end
2914 def visit_Arel_Nodes_On o, collector
2915 collector "ON "
2916 visit o.expr, collector
2917 end
2918 def visit_Arel_Nodes_Not o, collector
2919 collector "NOT ("
2920 visit(o.expr, collector) ")"
2921 end
2922 def visit_Arel_Table o, collector
2923 if o.table_alias
2924 else
2925 collector quote_table_name(o.name)
2926 end
2927 end
2928 def visit_Arel_Nodes_In o, collector
2929 if Array === o.right && o.right.empty?
2930 collector '1=0'
2931 else
2932 collector = visit o.left, collector
2933 collector " IN ("
2934 visit(o.right, collector) ")"
2935 end
2936 end
2937 def visit_Arel_Nodes_NotIn o, collector
2938 if Array === o.right && o.right.empty?
2939 collector '1=1'
2940 else
2941 collector = visit o.left, collector
2942 collector " NOT IN ("
2943 collector = visit o.right, collector
2944 collector ")"
2945 end
2946 end
2947 def visit_Arel_Nodes_And o, collector
2948 inject_join o.children, collector, " AND "
2949 end
2950 def visit_Arel_Nodes_Or o, collector
2951 collector = visit o.left, collector
2952 collector " OR "
2953 visit o.right, collector
2954 end
2955 def visit_Arel_Nodes_Assignment o, collector
2956 case o.right
2957 collector = visit o.left, collector
2958 collector " = "
2959 visit o.right, collector
2960 else
2961 collector = visit o.left, collector
2962 collector " = "
2963 collector quote(o.right, column_for(o.left)).to_s
2964 end
2965 end
2966 def visit_Arel_Nodes_Equality o, collector
2967 right = o.right
2968 collector = visit o.left, collector
2969 if right.nil?
2970 collector " IS NULL"
2971 else
2972 collector " = "
2973 visit right, collector
2974 end
2975 end
2976 def visit_Arel_Nodes_NotEqual o, collector
2977 right = o.right
2978 collector = visit o.left, collector
2979 if right.nil?
2980 collector " IS NOT NULL"
2981 else
2982 collector " != "
2983 visit right, collector
2984 end
2985 end
2986 def visit_Arel_Nodes_As o, collector
2987 collector = visit o.left, collector
2988 collector " AS "
2989 visit o.right, collector
2990 end
2991 collector "#{quote_column_name o.name}"
2992 collector
2993 end
2994 def visit_Arel_Attributes_Attribute o, collector
2995 end
2996 def literal o, collector; collector o.to_s; end
2997 def visit_Arel_Nodes_BindParam o, collector
2998 collector.add_bind(o) { "?" }
2999 end
3000 alias :visit_Arel_Nodes_SqlLiteral :literal
3001 alias :visit_Bignum :literal
3002 alias :visit_Fixnum :literal
3003 def quoted o, a
3004 if a && a.able_to_type_cast?
3005 quote(a.type_cast_for_database(o))
3006 else
3007 quote(o, column_for(a))
3008 end
3009 end
3010 def unsupported o, collector
3011 raise "unsupported: #{o.class.name}"
3012 end
3013 alias :visit_BigDecimal :unsupported
3014 alias :visit_Class :unsupported
3015 alias :visit_Date :unsupported
3016 alias :visit_DateTime :unsupported
3017 alias :visit_FalseClass :unsupported
3018 alias :visit_Float :unsupported
3019 alias :visit_Hash :unsupported
3020 alias :visit_NilClass :unsupported
3021 alias :visit_String :unsupported
3022 alias :visit_Symbol :unsupported
3023 alias :visit_Time :unsupported
3024 alias :visit_TrueClass :unsupported
3025 def visit_Arel_Nodes_InfixOperation o, collector
3026 collector = visit o.left, collector
3027 collector " #{o.operator} "
3028 visit o.right, collector
3029 end
3030 def visit_Array o, collector
3031 inject_join o, collector, ", "
3032 end
3033 alias :visit_Set :visit_Array
3034 def quote value, column = nil
3035 return value if Arel::Nodes::SqlLiteral === value
3036 if column
3037 print_type_cast_deprecation
3038 end
3039 @connection.quote value, column
3040 end
3041 def quote_table_name name
3042 return name if Arel::Nodes::SqlLiteral === name
3043 @connection.quote_table_name(name)
3044 end
3045 def quote_column_name name
3046 return name if Arel::Nodes::SqlLiteral === name
3047 @connection.quote_column_name(name)
3048 end
3049 def maybe_visit thing, collector
3050 return collector unless thing
3051 collector " "
3052 visit thing, collector
3053 end
3054 def inject_join list, collector, join_str
3055 len = list.length - 1
3056 if i == len
3057 visit x, c
3058 else
3059 visit(x, c) join_str
3060 end
3061 }
3062 end
3063 def infix_value o, collector, value
3064 collector = visit o.left, collector
3065 collector value
3066 visit o.right, collector
3067 end
3068 def aggregate name, o, collector
3069 collector "#{name}("
3070 if o.distinct
3071 collector "DISTINCT "
3072 end
3073 if o.alias
3074 collector " AS "
3075 visit o.alias, collector
3076 else
3077 collector
3078 end
3079 end
3080 def print_type_cast_deprecation
3081 warn -eowarn
3082 eowarn
3083 end
3084 end
3085 end
3086 end
3087 end
3088 module Arel
3089 module Visitors
3090 class Visitor
3091 def initialize
3092 @dispatch = get_dispatch_cache
3093 end
3094 def accept object
3095 visit object
3096 end
3097 private
3098 def self.dispatch_cache
3099 Hash.new do |hash, klass|
3100 end
3101 end
3102 def get_dispatch_cache
3103 self.class.dispatch_cache
3104 end
3105 def dispatch
3106 @dispatch
3107 end
3108 def visit object
3109 send dispatch[object.class], object
3110 rescue NoMethodError = e
3111 respond_to?(dispatch[klass], true)
3112 }
3113 dispatch[object.class] = dispatch[superklass]
3114 retry
3115 end
3116 end
3117 end
3118 end
3119 module Arel
3120 module Visitors
3121 class WhereSql Arel::Visitors::ToSql
3122 private
3123 def visit_Arel_Nodes_SelectCore o, collector
3124 collector "WHERE "
3125 inject_join o.wheres, collector, ' AND '
3126 end
3127 end
3128 end
3129 end
3130 require 'arel/visitors/visitor'
3131 require 'arel/visitors/depth_first'
3132 require 'arel/visitors/to_sql'
3133 require 'arel/visitors/sqlite'
3134 require 'arel/visitors/postgresql'
3135 require 'arel/visitors/mysql'
3136 require 'arel/visitors/mssql'
3137 require 'arel/visitors/oracle'
3138 require 'arel/visitors/where_sql'
3139 require 'arel/visitors/dot'
3140 require 'arel/visitors/ibm_db'
3141 require 'arel/visitors/informix'
3142 module Arel
3143 module Visitors
3144 VISITORS = {
3145 'postgresql' = Arel::Visitors::PostgreSQL,
3146 'mysql' = Arel::Visitors::MySQL,
3147 'mysql2' = Arel::Visitors::MySQL,
3148 'mssql' = Arel::Visitors::MSSQL,
3149 'sqlserver' = Arel::Visitors::MSSQL,
3150 'oracle_enhanced' = Arel::Visitors::Oracle,
3151 'sqlite' = Arel::Visitors::SQLite,
3152 'sqlite3' = Arel::Visitors::SQLite,
3153 'ibm_db' = Arel::Visitors::IBM_DB,
3154 'informix' = Arel::Visitors::Informix,
3155 }
3156 ENGINE_VISITORS = Hash.new do |hash, engine|
3157 pool = engine.connection_pool
3158 adapter = pool.spec.config[:adapter]
3159 end
3160 def self.visitor_for engine
3161 ENGINE_VISITORS[engine]
3162 end
3163 class self; alias :for :visitor_for; end
3164 end
3165 end
3166 module Arel
3167 module WindowPredications
3168 def over(expr = nil)
3169 Nodes::Over.new(self, expr)
3170 end
3171 end
3172 endrequire 'arel/crud'
3173 require 'arel/factory_methods'
3174 require 'arel/expressions'
3175 require 'arel/predications'
3176 require 'arel/window_predications'
3177 require 'arel/math'
3178 require 'arel/alias_predication'
3179 require 'arel/order_predications'
3180 require 'arel/table'
3181 require 'arel/attributes'
3182 require 'arel/compatibility/wheres'
3183 require 'arel/visitors'
3184 require 'arel/tree_manager'
3185 require 'arel/insert_manager'
3186 require 'arel/select_manager'
3187 require 'arel/update_manager'
3188 require 'arel/delete_manager'
3189 require 'arel/nodes'
3190 module Arel
3191 VERSION = '7.0.0.alpha'
3192 def self.sql raw_sql
3193 Arel::Nodes::SqlLiteral.new raw_sql
3194 end
3195 def self.star
3196 sql '*'
3197 end
3198 Node = Arel::Nodes::Node
3199 end
3200 require 'helper'
3201 require 'ostruct'
3202 module Arel
3203 module Attributes
3204 describe 'attribute' do
3205 describe '#not_eq' do
3206 relation = Table.new(:users)
3207 end
3208 relation = Table.new(:users)
3209 mgr = relation.project relation[:id]
3210 mgr.where relation[:id].not_eq(10)
3211 mgr.to_sql.must_be_like %{
3212 }
3213 end
3214 relation = Table.new(:users)
3215 mgr = relation.project relation[:id]
3216 mgr.where relation[:id].not_eq(nil)
3217 mgr.to_sql.must_be_like %{
3218 }
3219 end
3220 end
3221 describe '#not_eq_any' do
3222 relation = Table.new(:users)
3223 end
3224 relation = Table.new(:users)
3225 mgr = relation.project relation[:id]
3226 mgr.where relation[:id].not_eq_any([1,2])
3227 mgr.to_sql.must_be_like %{
3228 }
3229 end
3230 end
3231 describe '#not_eq_all' do
3232 relation = Table.new(:users)
3233 end
3234 relation = Table.new(:users)
3235 mgr = relation.project relation[:id]
3236 mgr.where relation[:id].not_eq_all([1,2])
3237 mgr.to_sql.must_be_like %{
3238 }
3239 end
3240 end
3241 describe '#gt' do
3242 relation = Table.new(:users)
3243 end
3244 relation = Table.new(:users)
3245 mgr = relation.project relation[:id]
3246 mgr.where relation[:id].gt(10)
3247 mgr.to_sql.must_be_like %{
3248 }
3249 end
3250 users = Table.new(:users)
3251 avg = users.project(users[:karma].average)
3252 mgr.to_sql.must_be_like %{
3253 }
3254 end
3255 relation = Table.new(:users)
3256 mgr = relation.project relation[:id]
3257 mgr.where relation[:name].gt('fake_name')
3258 current_time = ::Time.now
3259 mgr.where relation[:created_at].gt(current_time)
3260 end
3261 end
3262 describe '#gt_any' do
3263 relation = Table.new(:users)
3264 end
3265 relation = Table.new(:users)
3266 mgr = relation.project relation[:id]
3267 mgr.where relation[:id].gt_any([1,2])
3268 mgr.to_sql.must_be_like %{
3269 }
3270 end
3271 end
3272 describe '#gt_all' do
3273 relation = Table.new(:users)
3274 end
3275 relation = Table.new(:users)
3276 mgr = relation.project relation[:id]
3277 mgr.where relation[:id].gt_all([1,2])
3278 mgr.to_sql.must_be_like %{
3279 }
3280 end
3281 end
3282 describe '#gteq' do
3283 relation = Table.new(:users)
3284 end
3285 relation = Table.new(:users)
3286 mgr = relation.project relation[:id]
3287 mgr.where relation[:id].gteq(10)
3288 mgr.to_sql.must_be_like %{
3289 }
3290 end
3291 relation = Table.new(:users)
3292 mgr = relation.project relation[:id]
3293 mgr.where relation[:name].gteq('fake_name')
3294 current_time = ::Time.now
3295 end
3296 end
3297 describe '#gteq_any' do
3298 relation = Table.new(:users)
3299 end
3300 relation = Table.new(:users)
3301 mgr = relation.project relation[:id]
3302 mgr.where relation[:id].gteq_any([1,2])
3303 mgr.to_sql.must_be_like %{
3304 }
3305 end
3306 end
3307 describe '#gteq_all' do
3308 relation = Table.new(:users)
3309 end
3310 relation = Table.new(:users)
3311 mgr = relation.project relation[:id]
3312 mgr.where relation[:id].gteq_all([1,2])
3313 mgr.to_sql.must_be_like %{
3314 }
3315 end
3316 end
3317 describe '#lt' do
3318 relation = Table.new(:users)
3319 end
3320 relation = Table.new(:users)
3321 mgr = relation.project relation[:id]
3322 mgr.where relation[:id].lt(10)
3323 mgr.to_sql.must_be_like %{
3324 }
3325 end
3326 relation = Table.new(:users)
3327 mgr = relation.project relation[:id]
3328 mgr.where relation[:name].lt('fake_name')
3329 current_time = ::Time.now
3330 mgr.where relation[:created_at].lt(current_time)
3331 end
3332 end
3333 describe '#lt_any' do
3334 relation = Table.new(:users)
3335 end
3336 relation = Table.new(:users)
3337 mgr = relation.project relation[:id]
3338 mgr.where relation[:id].lt_any([1,2])
3339 mgr.to_sql.must_be_like %{
3340 }
3341 end
3342 end
3343 describe '#lt_all' do
3344 relation = Table.new(:users)
3345 end
3346 relation = Table.new(:users)
3347 mgr = relation.project relation[:id]
3348 mgr.where relation[:id].lt_all([1,2])
3349 mgr.to_sql.must_be_like %{
3350 }
3351 end
3352 end
3353 describe '#lteq' do
3354 relation = Table.new(:users)
3355 end
3356 relation = Table.new(:users)
3357 mgr = relation.project relation[:id]
3358 mgr.where relation[:id].lteq(10)
3359 mgr.to_sql.must_be_like %{
3360 }
3361 end
3362 relation = Table.new(:users)
3363 mgr = relation.project relation[:id]
3364 mgr.where relation[:name].lteq('fake_name')
3365 current_time = ::Time.now
3366 end
3367 end
3368 describe '#lteq_any' do
3369 relation = Table.new(:users)
3370 end
3371 relation = Table.new(:users)
3372 mgr = relation.project relation[:id]
3373 mgr.where relation[:id].lteq_any([1,2])
3374 mgr.to_sql.must_be_like %{
3375 }
3376 end
3377 end
3378 describe '#lteq_all' do
3379 relation = Table.new(:users)
3380 end
3381 relation = Table.new(:users)
3382 mgr = relation.project relation[:id]
3383 mgr.where relation[:id].lteq_all([1,2])
3384 mgr.to_sql.must_be_like %{
3385 }
3386 end
3387 end
3388 describe '#average' do
3389 relation = Table.new(:users)
3390 relation[:id].average.must_be_kind_of Nodes::Avg
3391 end
3392 relation = Table.new(:users)
3393 mgr = relation.project relation[:id].average
3394 mgr.to_sql.must_be_like %{
3395 SELECT AVG("users"."id")
3396 FROM "users"
3397 }
3398 end
3399 end
3400 describe '#maximum' do
3401 relation = Table.new(:users)
3402 relation[:id].maximum.must_be_kind_of Nodes::Max
3403 end
3404 relation = Table.new(:users)
3405 mgr = relation.project relation[:id].maximum
3406 mgr.to_sql.must_be_like %{
3407 SELECT MAX("users"."id")
3408 FROM "users"
3409 }
3410 end
3411 end
3412 describe '#minimum' do
3413 relation = Table.new(:users)
3414 relation[:id].minimum.must_be_kind_of Nodes::Min
3415 end
3416 end
3417 describe '#sum' do
3418 relation = Table.new(:users)
3419 relation[:id].sum.must_be_kind_of Nodes::Sum
3420 end
3421 relation = Table.new(:users)
3422 mgr = relation.project relation[:id].sum
3423 mgr.to_sql.must_be_like %{
3424 SELECT SUM("users"."id")
3425 FROM "users"
3426 }
3427 end
3428 end
3429 describe '#count' do
3430 relation = Table.new(:users)
3431 relation[:id].count.must_be_kind_of Nodes::Count
3432 end
3433 relation = Table.new(:users)
3434 count = relation[:id].count(nil)
3435 count.must_be_kind_of Nodes::Count
3436 count.distinct.must_be_nil
3437 end
3438 end
3439 describe '#eq' do
3440 attribute = Attribute.new nil, nil
3441 equality = attribute.eq 1
3442 equality.left.must_equal attribute
3443 equality.right.val.must_equal 1
3444 equality.must_be_kind_of Nodes::Equality
3445 end
3446 relation = Table.new(:users)
3447 mgr = relation.project relation[:id]
3448 mgr.where relation[:id].eq(10)
3449 mgr.to_sql.must_be_like %{
3450 }
3451 end
3452 relation = Table.new(:users)
3453 mgr = relation.project relation[:id]
3454 mgr.where relation[:id].eq(nil)
3455 mgr.to_sql.must_be_like %{
3456 }
3457 end
3458 end
3459 describe '#eq_any' do
3460 relation = Table.new(:users)
3461 end
3462 relation = Table.new(:users)
3463 mgr = relation.project relation[:id]
3464 mgr.where relation[:id].eq_any([1,2])
3465 mgr.to_sql.must_be_like %{
3466 }
3467 end
3468 relation = Table.new(:users)
3469 mgr = relation.project relation[:id]
3470 values = [1,2]
3471 mgr.where relation[:id].eq_any(values)
3472 values.must_equal [1,2]
3473 end
3474 end
3475 describe '#eq_all' do
3476 relation = Table.new(:users)
3477 end
3478 relation = Table.new(:users)
3479 mgr = relation.project relation[:id]
3480 mgr.where relation[:id].eq_all([1,2])
3481 mgr.to_sql.must_be_like %{
3482 }
3483 end
3484 relation = Table.new(:users)
3485 mgr = relation.project relation[:id]
3486 values = [1,2]
3487 mgr.where relation[:id].eq_all(values)
3488 values.must_equal [1,2]
3489 end
3490 end
3491 describe '#matches' do
3492 relation = Table.new(:users)
3493 end
3494 relation = Table.new(:users)
3495 mgr = relation.project relation[:id]
3496 mgr.where relation[:name].matches('%bacon%')
3497 mgr.to_sql.must_be_like %{
3498 }
3499 end
3500 end
3501 describe '#matches_any' do
3502 relation = Table.new(:users)
3503 end
3504 relation = Table.new(:users)
3505 mgr = relation.project relation[:id]
3506 mgr.to_sql.must_be_like %{
3507 }
3508 end
3509 end
3510 describe '#matches_all' do
3511 relation = Table.new(:users)
3512 end
3513 relation = Table.new(:users)
3514 mgr = relation.project relation[:id]
3515 mgr.to_sql.must_be_like %{
3516 }
3517 end
3518 end
3519 describe '#does_not_match' do
3520 relation = Table.new(:users)
3521 end
3522 relation = Table.new(:users)
3523 mgr = relation.project relation[:id]
3524 mgr.to_sql.must_be_like %{
3525 }
3526 end
3527 end
3528 describe '#does_not_match_any' do
3529 relation = Table.new(:users)
3530 end
3531 relation = Table.new(:users)
3532 mgr = relation.project relation[:id]
3533 mgr.to_sql.must_be_like %{
3534 }
3535 end
3536 end
3537 describe '#does_not_match_all' do
3538 relation = Table.new(:users)
3539 end
3540 relation = Table.new(:users)
3541 mgr = relation.project relation[:id]
3542 mgr.to_sql.must_be_like %{
3543 }
3544 end
3545 end
3546 describe 'with a range' do
3547 attribute = Attribute.new nil, nil
3548 node = attribute.between(1..3)
3549 node.must_equal Nodes::Between.new(
3550 attribute,
3551 Nodes::And.new([
3552 Nodes::Casted.new(1, attribute),
3553 Nodes::Casted.new(3, attribute)
3554 ])
3555 )
3556 end
3557 attribute = Attribute.new nil, nil
3558 node = attribute.between(-::Float::INFINITY..3)
3559 node.must_equal Nodes::LessThanOrEqual.new(
3560 attribute,
3561 Nodes::Casted.new(3, attribute)
3562 )
3563 end
3564 attribute = Attribute.new nil, nil
3565 node.must_equal Nodes::LessThanOrEqual.new(
3566 attribute,
3567 Nodes::Quoted.new(3)
3568 )
3569 end
3570 attribute = Attribute.new nil, nil
3571 node = attribute.between(-::Float::INFINITY...3)
3572 node.must_equal Nodes::LessThan.new(
3573 attribute,
3574 Nodes::Casted.new(3, attribute)
3575 )
3576 end
3577 attribute = Attribute.new nil, nil
3578 node.must_equal Nodes::LessThan.new(
3579 attribute,
3580 Nodes::Quoted.new(3)
3581 )
3582 end
3583 attribute = Attribute.new nil, nil
3584 node.must_equal Nodes::NotIn.new(attribute, [])
3585 end
3586 attribute = Attribute.new nil, nil
3587 node.must_equal Nodes::NotIn.new(attribute, [])
3588 end
3589 attribute = Attribute.new nil, nil
3590 node = attribute.between(0..::Float::INFINITY)
3591 node.must_equal Nodes::GreaterThanOrEqual.new(
3592 attribute,
3593 Nodes::Casted.new(0, attribute)
3594 )
3595 end
3596 attribute = Attribute.new nil, nil
3597 node.must_equal Nodes::GreaterThanOrEqual.new(
3598 attribute,
3599 Nodes::Quoted.new(0)
3600 )
3601 end
3602 attribute = Attribute.new nil, nil
3603 node = attribute.between(0...3)
3604 node.must_equal Nodes::And.new([
3605 Nodes::GreaterThanOrEqual.new(
3606 attribute,
3607 Nodes::Casted.new(0, attribute)
3608 ),
3609 Nodes::LessThan.new(
3610 attribute,
3611 Nodes::Casted.new(3, attribute)
3612 )
3613 ])
3614 end
3615 def quoted_range(begin_val, end_val, exclude)
3616 OpenStruct.new(
3617 begin: Nodes::Quoted.new(begin_val),
3618 end: Nodes::Quoted.new(end_val),
3619 exclude_end?: exclude,
3620 )
3621 end
3622 end
3623 describe '#in' do
3624 relation = Table.new(:users)
3625 mgr = relation.project relation[:id]
3626 attribute = Attribute.new nil, nil
3627 node = attribute.in(mgr)
3628 node.must_equal Nodes::In.new(attribute, mgr.ast)
3629 end
3630 attribute = Attribute.new nil, nil
3631 node = attribute.in([1, 2, 3])
3632 node.must_equal Nodes::In.new(
3633 attribute,
3634 [
3635 Nodes::Casted.new(1, attribute),
3636 Nodes::Casted.new(2, attribute),
3637 Nodes::Casted.new(3, attribute),
3638 ]
3639 )
3640 end
3641 attribute = Attribute.new nil, nil
3642 random_object = Object.new
3643 node = attribute.in(random_object)
3644 node.must_equal Nodes::In.new(
3645 attribute,
3646 Nodes::Casted.new(random_object, attribute)
3647 )
3648 end
3649 relation = Table.new(:users)
3650 mgr = relation.project relation[:id]
3651 mgr.where relation[:id].in([1,2,3])
3652 mgr.to_sql.must_be_like %{
3653 }
3654 end
3655 end
3656 describe '#in_any' do
3657 relation = Table.new(:users)
3658 end
3659 relation = Table.new(:users)
3660 mgr = relation.project relation[:id]
3661 mgr.where relation[:id].in_any([[1,2], [3,4]])
3662 mgr.to_sql.must_be_like %{
3663 }
3664 end
3665 end
3666 describe '#in_all' do
3667 relation = Table.new(:users)
3668 end
3669 relation = Table.new(:users)
3670 mgr = relation.project relation[:id]
3671 mgr.where relation[:id].in_all([[1,2], [3,4]])
3672 mgr.to_sql.must_be_like %{
3673 }
3674 end
3675 end
3676 describe 'with a range' do
3677 attribute = Attribute.new nil, nil
3678 node = attribute.not_between(1..3)
3679 Nodes::LessThan.new(
3680 attribute,
3681 Nodes::Casted.new(1, attribute)
3682 ),
3683 Nodes::GreaterThan.new(
3684 attribute,
3685 Nodes::Casted.new(3, attribute)
3686 )
3687 ))
3688 end
3689 attribute = Attribute.new nil, nil
3690 node.must_equal Nodes::GreaterThan.new(
3691 attribute,
3692 Nodes::Casted.new(3, attribute)
3693 )
3694 end
3695 attribute = Attribute.new nil, nil
3696 node.must_equal Nodes::GreaterThanOrEqual.new(
3697 attribute,
3698 Nodes::Casted.new(3, attribute)
3699 )
3700 end
3701 attribute = Attribute.new nil, nil
3702 node.must_equal Nodes::In.new(attribute, [])
3703 end
3704 attribute = Attribute.new nil, nil
3705 node.must_equal Nodes::LessThan.new(
3706 attribute,
3707 Nodes::Casted.new(0, attribute)
3708 )
3709 end
3710 attribute = Attribute.new nil, nil
3711 node = attribute.not_between(0...3)
3712 Nodes::LessThan.new(
3713 attribute,
3714 Nodes::Casted.new(0, attribute)
3715 ),
3716 Nodes::GreaterThanOrEqual.new(
3717 attribute,
3718 Nodes::Casted.new(3, attribute)
3719 )
3720 ))
3721 end
3722 end
3723 describe '#not_in' do
3724 relation = Table.new(:users)
3725 mgr = relation.project relation[:id]
3726 attribute = Attribute.new nil, nil
3727 node = attribute.not_in(mgr)
3728 end
3729 attribute = Attribute.new nil, nil
3730 node = attribute.not_in([1, 2, 3])
3731 node.must_equal Nodes::NotIn.new(
3732 attribute,
3733 [
3734 Nodes::Casted.new(1, attribute),
3735 Nodes::Casted.new(2, attribute),
3736 Nodes::Casted.new(3, attribute),
3737 ]
3738 )
3739 end
3740 attribute = Attribute.new nil, nil
3741 random_object = Object.new
3742 node = attribute.not_in(random_object)
3743 node.must_equal Nodes::NotIn.new(
3744 attribute,
3745 Nodes::Casted.new(random_object, attribute)
3746 )
3747 end
3748 relation = Table.new(:users)
3749 mgr = relation.project relation[:id]
3750 mgr.where relation[:id].not_in([1,2,3])
3751 mgr.to_sql.must_be_like %{
3752 }
3753 end
3754 end
3755 describe '#not_in_any' do
3756 relation = Table.new(:users)
3757 end
3758 relation = Table.new(:users)
3759 mgr = relation.project relation[:id]
3760 mgr.to_sql.must_be_like %{
3761 }
3762 end
3763 end
3764 describe '#not_in_all' do
3765 relation = Table.new(:users)
3766 end
3767 relation = Table.new(:users)
3768 mgr = relation.project relation[:id]
3769 mgr.to_sql.must_be_like %{
3770 }
3771 end
3772 end
3773 describe '#eq_all' do
3774 relation = Table.new(:users)
3775 end
3776 relation = Table.new(:users)
3777 mgr = relation.project relation[:id]
3778 mgr.where relation[:id].eq_all([1,2])
3779 mgr.to_sql.must_be_like %{
3780 }
3781 end
3782 end
3783 describe '#asc' do
3784 relation = Table.new(:users)
3785 end
3786 relation = Table.new(:users)
3787 mgr = relation.project relation[:id]
3788 mgr.order relation[:id].asc
3789 mgr.to_sql.must_be_like %{
3790 }
3791 end
3792 end
3793 describe '#desc' do
3794 relation = Table.new(:users)
3795 end
3796 relation = Table.new(:users)
3797 mgr = relation.project relation[:id]
3798 mgr.order relation[:id].desc
3799 mgr.to_sql.must_be_like %{
3800 }
3801 end
3802 end
3803 end
3804 describe 'equality' do
3805 describe '#to_sql' do
3806 table = Table.new :users
3807 condition = table['id'].eq 1
3808 condition.to_sql.must_equal '"users"."id" = 1'
3809 end
3810 end
3811 end
3812 describe 'type casting' do
3813 table = Table.new(:foo)
3814 condition = table["id"].eq("1")
3815 refute table.able_to_type_cast?
3816 condition.to_sql.must_equal %("foo"."id" = '1')
3817 end
3818 fake_caster = Object.new
3819 if attr_name == "id"
3820 value.to_i
3821 else
3822 value
3823 end
3824 end
3825 table = Table.new(:foo, type_caster: fake_caster)
3826 assert table.able_to_type_cast?
3827 end
3828 table = Table.new(:users)
3829 condition = table["id"].eq("1")
3830 refute table.able_to_type_cast?
3831 condition.to_sql.must_equal %("users"."id" = 1)
3832 end
3833 end
3834 end
3835 end
3836 require 'helper'
3837 require 'arel/collectors/bind'
3838 module Arel
3839 module Collectors
3840 class TestBindCollector Arel::Test
3841 def setup
3842 @conn = FakeRecord::Base.new
3843 @visitor = Visitors::ToSql.new @conn.connection
3844 super
3845 end
3846 def collect node
3847 @visitor.accept(node, Collectors::Bind.new)
3848 end
3849 def compile node
3850 collect(node).value
3851 end
3852 def ast_with_binds bv
3853 table = Table.new(:users)
3854 manager = Arel::SelectManager.new table
3855 manager.where(table[:age].eq(bv))
3856 manager.where(table[:name].eq(bv))
3857 manager.ast
3858 end
3859 def test_leaves_binds
3860 node = Nodes::BindParam.new
3861 list = compile node
3862 assert_equal node, list.first
3863 assert_equal node.class, list.first.class
3864 end
3865 def test_adds_strings
3866 bv = Nodes::BindParam.new
3867 list = compile ast_with_binds bv
3868 assert_operator list.length, :, 0
3869 end
3870 def test_substitute_binds
3871 bv = Nodes::BindParam.new
3872 collector = collect ast_with_binds bv
3873 values = collector.value
3874 offsets = values.map.with_index { |v,i|
3875 [v,i]
3876 assert_equal "hello", list[offsets[0]]
3877 assert_equal "world", list[offsets[1]]
3878 end
3879 def test_compile
3880 bv = Nodes::BindParam.new
3881 collector = collect ast_with_binds bv
3882 sql = collector.compile ["hello", "world"]
3883 end
3884 end
3885 end
3886 end
3887 require 'helper'
3888 require 'arel/collectors/bind'
3889 module Arel
3890 module Collectors
3891 class TestSqlString Arel::Test
3892 def setup
3893 @conn = FakeRecord::Base.new
3894 @visitor = Visitors::ToSql.new @conn.connection
3895 super
3896 end
3897 def collect node
3898 @visitor.accept(node, Collectors::SQLString.new)
3899 end
3900 def compile node
3901 collect(node).value
3902 end
3903 def ast_with_binds bv
3904 table = Table.new(:users)
3905 manager = Arel::SelectManager.new table
3906 manager.where(table[:age].eq(bv))
3907 manager.where(table[:name].eq(bv))
3908 manager.ast
3909 end
3910 def test_compile
3911 bv = Nodes::BindParam.new
3912 collector = collect ast_with_binds bv
3913 sql = collector.compile ["hello", "world"]
3914 end
3915 end
3916 end
3917 end
3918 require 'rubygems'
3919 require 'minitest/autorun'
3920 require 'fileutils'
3921 require 'arel'
3922 require 'support/fake_record'
3923 Arel::Table.engine = FakeRecord::Base.new
3924 $arel_silence_type_casting_deprecation = true
3925 class Object
3926 def must_be_like other
3927 end
3928 end
3929 module Arel
3930 class Test MiniTest::Test
3931 def assert_like expected, actual
3932 assert_equal expected.gsub(/\s+/, ' ').strip,
3933 actual.gsub(/\s+/, ' ').strip
3934 end
3935 end
3936 end
3937 require 'helper'
3938 module Arel
3939 module Nodes
3940 describe 'And' do
3941 describe 'equality' do
3942 assert_equal 1, array.uniq.size
3943 end
3944 assert_equal 2, array.uniq.size
3945 end
3946 end
3947 end
3948 end
3949 end
3950 require 'helper'
3951 module Arel
3952 module Nodes
3953 describe 'As' do
3954 describe '#as' do
3955 attr = Table.new(:users)[:id]
3956 as = attr.as(Arel.sql('foo'))
3957 assert_equal attr, as.left
3958 assert_equal 'foo', as.right
3959 end
3960 attr = Table.new(:users)[:id]
3961 as = attr.as('foo')
3962 assert_kind_of Arel::Nodes::SqlLiteral, as.right
3963 end
3964 end
3965 describe 'equality' do
3966 assert_equal 1, array.uniq.size
3967 end
3968 assert_equal 2, array.uniq.size
3969 end
3970 end
3971 end
3972 end
3973 end
3974 require 'helper'
3975 module Arel
3976 module Nodes
3977 class TestAscending Minitest::Test
3978 def test_construct
3979 ascending = Ascending.new 'zomg'
3980 assert_equal 'zomg', ascending.expr
3981 end
3982 def test_reverse
3983 ascending = Ascending.new 'zomg'
3984 descending = ascending.reverse
3985 assert_kind_of Descending, descending
3986 assert_equal ascending.expr, descending.expr
3987 end
3988 def test_direction
3989 ascending = Ascending.new 'zomg'
3990 assert_equal :asc, ascending.direction
3991 end
3992 def test_ascending?
3993 ascending = Ascending.new 'zomg'
3994 assert ascending.ascending?
3995 end
3996 def test_descending?
3997 ascending = Ascending.new 'zomg'
3998 assert !ascending.descending?
3999 end
4000 def test_equality_with_same_ivars
4001 assert_equal 1, array.uniq.size
4002 end
4003 def test_inequality_with_different_ivars
4004 assert_equal 2, array.uniq.size
4005 end
4006 end
4007 end
4008 end
4009 require 'helper'
4010 module Arel
4011 module Nodes
4012 class TestBin Minitest::Test
4013 def test_new
4014 assert Arel::Nodes::Bin.new('zomg')
4015 end
4016 def test_default_to_sql
4017 node = Arel::Nodes::Bin.new(Arel.sql('zomg'))
4018 end
4019 def test_mysql_to_sql
4020 node = Arel::Nodes::Bin.new(Arel.sql('zomg'))
4021 end
4022 def test_equality_with_same_ivars
4023 array = [Bin.new('zomg'), Bin.new('zomg')]
4024 assert_equal 1, array.uniq.size
4025 end
4026 def test_inequality_with_different_ivars
4027 array = [Bin.new('zomg'), Bin.new('zomg!')]
4028 assert_equal 2, array.uniq.size
4029 end
4030 end
4031 end
4032 end
4033 require 'helper'
4034 require 'set'
4035 module Arel
4036 module Nodes
4037 describe 'Binary' do
4038 describe '#hash' do
4039 eq = Equality.new('foo', 'bar')
4040 eq2 = Equality.new('foo', 'bar')
4041 eq3 = Equality.new('bar', 'baz')
4042 assert_equal eq.hash, eq2.hash
4043 refute_equal eq.hash, eq3.hash
4044 end
4045 eq = Equality.new('foo', 'bar')
4046 neq = NotEqual.new('foo', 'bar')
4047 refute_equal eq.hash, neq.hash
4048 end
4049 end
4050 end
4051 end
4052 end
4053 require 'helper'
4054 module Arel
4055 module Nodes
4056 describe 'BindParam' do
4057 BindParam.new.must_equal(BindParam.new)
4058 end
4059 BindParam.new.wont_equal(Node.new)
4060 end
4061 end
4062 end
4063 end
4064 require 'helper'
4065 describe Arel::Nodes::Count do
4066 describe "as" do
4067 table = Arel::Table.new :users
4068 table[:id].count.as('foo').to_sql.must_be_like %{
4069 COUNT("users"."id") AS foo
4070 }
4071 end
4072 end
4073 describe "eq" do
4074 table = Arel::Table.new :users
4075 table[:id].count.eq(2).to_sql.must_be_like %{
4076 COUNT("users"."id") = 2
4077 }
4078 end
4079 end
4080 describe 'equality' do
4081 assert_equal 1, array.uniq.size
4082 end
4083 assert_equal 2, array.uniq.size
4084 end
4085 end
4086 end
4087 require 'helper'
4088 describe Arel::Nodes::DeleteStatement do
4089 describe "#clone" do
4090 statement = Arel::Nodes::DeleteStatement.new
4091 statement.wheres = %w[a b c]
4092 dolly = statement.clone
4093 dolly.wheres.must_equal statement.wheres
4094 dolly.wheres.wont_be_same_as statement.wheres
4095 end
4096 end
4097 describe 'equality' do
4098 statement1 = Arel::Nodes::DeleteStatement.new
4099 statement1.wheres = %w[a b c]
4100 statement2 = Arel::Nodes::DeleteStatement.new
4101 statement2.wheres = %w[a b c]
4102 array = [statement1, statement2]
4103 assert_equal 1, array.uniq.size
4104 end
4105 statement1 = Arel::Nodes::DeleteStatement.new
4106 statement1.wheres = %w[a b c]
4107 statement2 = Arel::Nodes::DeleteStatement.new
4108 statement2.wheres = %w[1 2 3]
4109 array = [statement1, statement2]
4110 assert_equal 2, array.uniq.size
4111 end
4112 end
4113 end
4114 require 'helper'
4115 module Arel
4116 module Nodes
4117 class TestDescending Minitest::Test
4118 def test_construct
4119 descending = Descending.new 'zomg'
4120 assert_equal 'zomg', descending.expr
4121 end
4122 def test_reverse
4123 descending = Descending.new 'zomg'
4124 ascending = descending.reverse
4125 assert_kind_of Ascending, ascending
4126 assert_equal descending.expr, ascending.expr
4127 end
4128 def test_direction
4129 descending = Descending.new 'zomg'
4130 assert_equal :desc, descending.direction
4131 end
4132 def test_ascending?
4133 descending = Descending.new 'zomg'
4134 assert !descending.ascending?
4135 end
4136 def test_descending?
4137 descending = Descending.new 'zomg'
4138 assert descending.descending?
4139 end
4140 def test_equality_with_same_ivars
4141 assert_equal 1, array.uniq.size
4142 end
4143 def test_inequality_with_different_ivars
4144 assert_equal 2, array.uniq.size
4145 end
4146 end
4147 end
4148 end
4149 require 'helper'
4150 module Arel
4151 module Nodes
4152 describe 'Distinct' do
4153 describe 'equality' do
4154 array = [Distinct.new, Distinct.new]
4155 assert_equal 1, array.uniq.size
4156 end
4157 array = [Distinct.new, Node.new]
4158 assert_equal 2, array.uniq.size
4159 end
4160 end
4161 end
4162 end
4163 end
4164 require 'helper'
4165 module Arel
4166 module Nodes
4167 describe 'equality' do
4168 describe 'backwards compat' do
4169 describe 'operator' do
4170 attr = Table.new(:users)[:id]
4171 left = attr.eq(10)
4172 left.operator.must_equal :==
4173 end
4174 end
4175 describe 'operand1' do
4176 attr = Table.new(:users)[:id]
4177 left = attr.eq(10)
4178 left.left.must_equal left.operand1
4179 end
4180 end
4181 describe 'operand2' do
4182 attr = Table.new(:users)[:id]
4183 left = attr.eq(10)
4184 left.right.must_equal left.operand2
4185 end
4186 end
4187 describe 'to_sql' do
4188 engine = FakeRecord::Base.new
4189 engine.connection.extend Module.new {
4190 attr_accessor :quote_count
4191 def quote(*args) @quote_count += 1; super; end
4192 }
4193 engine.connection.quote_count = 0
4194 attr = Table.new(:users)[:id]
4195 test = attr.eq(10)
4196 test.to_sql engine
4197 engine.connection.quote_count.must_equal 3
4198 end
4199 end
4200 end
4201 describe 'or' do
4202 attr = Table.new(:users)[:id]
4203 left = attr.eq(10)
4204 right = attr.eq(11)
4205 node = left.or right
4206 node.expr.left.must_equal left
4207 node.expr.right.must_equal right
4208 end
4209 end
4210 describe 'and' do
4211 attr = Table.new(:users)[:id]
4212 left = attr.eq(10)
4213 right = attr.eq(11)
4214 node = left.and right
4215 node.left.must_equal left
4216 node.right.must_equal right
4217 end
4218 end
4219 assert_equal 1, array.uniq.size
4220 end
4221 assert_equal 2, array.uniq.size
4222 end
4223 end
4224 end
4225 end
4226 require 'helper'
4227 describe Arel::Nodes::Extract do
4228 table = Arel::Table.new :users
4229 EXTRACT(DATE FROM "users"."timestamp")
4230 }
4231 end
4232 describe "as" do
4233 table = Arel::Table.new :users
4234 EXTRACT(DATE FROM "users"."timestamp") AS foo
4235 }
4236 end
4237 table = Arel::Table.new :users
4238 extract = table[:timestamp].extract('date')
4239 before = extract.dup
4240 extract.as('foo')
4241 assert_equal extract, before
4242 end
4243 end
4244 describe 'equality' do
4245 table = Arel::Table.new :users
4246 assert_equal 1, array.uniq.size
4247 end
4248 table = Arel::Table.new :users
4249 assert_equal 2, array.uniq.size
4250 end
4251 end
4252 end
4253 require 'helper'
4254 module Arel
4255 module Nodes
4256 describe 'False' do
4257 describe 'equality' do
4258 array = [False.new, False.new]
4259 assert_equal 1, array.uniq.size
4260 end
4261 array = [False.new, Node.new]
4262 assert_equal 2, array.uniq.size
4263 end
4264 end
4265 end
4266 end
4267 end
4268 require 'helper'
4269 module Arel
4270 module Nodes
4271 describe 'Grouping' do
4272 end
4273 describe 'equality' do
4274 assert_equal 1, array.uniq.size
4275 end
4276 assert_equal 2, array.uniq.size
4277 end
4278 end
4279 end
4280 end
4281 end
4282 require 'helper'
4283 module Arel
4284 module Nodes
4285 class TestInfixOperation Minitest::Test
4286 def test_construct
4287 operation = InfixOperation.new :+, 1, 2
4288 assert_equal :+, operation.operator
4289 assert_equal 1, operation.left
4290 assert_equal 2, operation.right
4291 end
4292 def test_operation_alias
4293 operation = InfixOperation.new :+, 1, 2
4294 aliaz = operation.as('zomg')
4295 assert_kind_of As, aliaz
4296 assert_equal operation, aliaz.left
4297 assert_equal 'zomg', aliaz.right
4298 end
4299 def test_operation_ordering
4300 operation = InfixOperation.new :+, 1, 2
4301 ordering = operation.desc
4302 assert_kind_of Descending, ordering
4303 assert_equal operation, ordering.expr
4304 assert ordering.descending?
4305 end
4306 def test_equality_with_same_ivars
4307 assert_equal 1, array.uniq.size
4308 end
4309 def test_inequality_with_different_ivars
4310 assert_equal 2, array.uniq.size
4311 end
4312 end
4313 end
4314 end
4315 require 'helper'
4316 describe Arel::Nodes::InsertStatement do
4317 describe "#clone" do
4318 statement = Arel::Nodes::InsertStatement.new
4319 statement.columns = %w[a b c]
4320 statement.values = %w[x y z]
4321 dolly = statement.clone
4322 dolly.columns.must_equal statement.columns
4323 dolly.values.must_equal statement.values
4324 dolly.columns.wont_be_same_as statement.columns
4325 dolly.values.wont_be_same_as statement.values
4326 end
4327 end
4328 describe 'equality' do
4329 statement1 = Arel::Nodes::InsertStatement.new
4330 statement1.columns = %w[a b c]
4331 statement1.values = %w[x y z]
4332 statement2 = Arel::Nodes::InsertStatement.new
4333 statement2.columns = %w[a b c]
4334 statement2.values = %w[x y z]
4335 array = [statement1, statement2]
4336 assert_equal 1, array.uniq.size
4337 end
4338 statement1 = Arel::Nodes::InsertStatement.new
4339 statement1.columns = %w[a b c]
4340 statement1.values = %w[x y z]
4341 statement2 = Arel::Nodes::InsertStatement.new
4342 statement2.columns = %w[a b c]
4343 statement2.values = %w[1 2 3]
4344 array = [statement1, statement2]
4345 assert_equal 2, array.uniq.size
4346 end
4347 end
4348 end
4349 require 'helper'
4350 module Arel
4351 module Nodes
4352 class TestNamedFunction Minitest::Test
4353 def test_construct
4354 function = NamedFunction.new 'omg', 'zomg'
4355 assert_equal 'omg', function.name
4356 assert_equal 'zomg', function.expressions
4357 end
4358 def test_function_alias
4359 function = NamedFunction.new 'omg', 'zomg'
4360 function = function.as('wth')
4361 assert_equal 'omg', function.name
4362 assert_equal 'zomg', function.expressions
4363 assert_kind_of SqlLiteral, function.alias
4364 assert_equal 'wth', function.alias
4365 end
4366 def test_construct_with_alias
4367 function = NamedFunction.new 'omg', 'zomg', 'wth'
4368 assert_equal 'omg', function.name
4369 assert_equal 'zomg', function.expressions
4370 assert_kind_of SqlLiteral, function.alias
4371 assert_equal 'wth', function.alias
4372 end
4373 def test_equality_with_same_ivars
4374 array = [
4375 NamedFunction.new('omg', 'zomg', 'wth'),
4376 NamedFunction.new('omg', 'zomg', 'wth')
4377 ]
4378 assert_equal 1, array.uniq.size
4379 end
4380 def test_inequality_with_different_ivars
4381 array = [
4382 NamedFunction.new('omg', 'zomg', 'wth'),
4383 NamedFunction.new('zomg', 'zomg', 'wth')
4384 ]
4385 assert_equal 2, array.uniq.size
4386 end
4387 end
4388 end
4389 end
4390 require 'helper'
4391 module Arel
4392 class TestNode Minitest::Test
4393 def test_includes_factory_methods
4394 assert Node.new.respond_to?(:create_join)
4395 end
4396 def test_all_nodes_are_nodes
4397 Nodes.constants.map { |k|
4398 Nodes.const_get(k)
4399 }.grep(Class).each do |klass|
4400 next if Nodes::SqlLiteral == klass
4401 next if Nodes::BindParam == klass
4402 next if klass.name =~ /^Arel::Nodes::Test/
4403 end
4404 end
4405 def test_each
4406 list = []
4407 node = Nodes::Node.new
4408 node.each { |n| list n }
4409 assert_equal [node], list
4410 end
4411 def test_generator
4412 list = []
4413 node = Nodes::Node.new
4414 node.each.each { |n| list n }
4415 assert_equal [node], list
4416 end
4417 def test_enumerable
4418 node = Nodes::Node.new
4419 assert_kind_of Enumerable, node
4420 end
4421 end
4422 end
4423 require 'helper'
4424 module Arel
4425 module Nodes
4426 describe 'not' do
4427 describe '#not' do
4428 attr = Table.new(:users)[:id]
4429 expr = attr.eq(10)
4430 node = expr.not
4431 node.must_be_kind_of Not
4432 node.expr.must_equal expr
4433 end
4434 end
4435 describe 'equality' do
4436 array = [Not.new('foo'), Not.new('foo')]
4437 assert_equal 1, array.uniq.size
4438 end
4439 array = [Not.new('foo'), Not.new('baz')]
4440 assert_equal 2, array.uniq.size
4441 end
4442 end
4443 end
4444 end
4445 end
4446 require 'helper'
4447 module Arel
4448 module Nodes
4449 describe 'or' do
4450 describe '#or' do
4451 attr = Table.new(:users)[:id]
4452 left = attr.eq(10)
4453 right = attr.eq(11)
4454 node = left.or right
4455 node.expr.left.must_equal left
4456 node.expr.right.must_equal right
4457 oror = node.or(right)
4458 oror.expr.left.must_equal node
4459 oror.expr.right.must_equal right
4460 end
4461 end
4462 describe 'equality' do
4463 assert_equal 1, array.uniq.size
4464 end
4465 assert_equal 2, array.uniq.size
4466 end
4467 end
4468 end
4469 end
4470 end
4471 require 'helper'
4472 describe Arel::Nodes::Over do
4473 describe 'as' do
4474 table = Arel::Table.new :users
4475 COUNT("users"."id") OVER () AS foo
4476 }
4477 end
4478 end
4479 describe 'with literal' do
4480 table = Arel::Table.new :users
4481 COUNT("users"."id") OVER "foo"
4482 }
4483 end
4484 end
4485 describe 'with SQL literal' do
4486 table = Arel::Table.new :users
4487 COUNT("users"."id") OVER foo
4488 }
4489 end
4490 end
4491 describe 'with no expression' do
4492 table = Arel::Table.new :users
4493 table[:id].count.over.to_sql.must_be_like %{
4494 COUNT("users"."id") OVER ()
4495 }
4496 end
4497 end
4498 describe 'with expression' do
4499 table = Arel::Table.new :users
4500 }
4501 end
4502 end
4503 describe 'equality' do
4504 array = [
4505 Arel::Nodes::Over.new('foo', 'bar'),
4506 Arel::Nodes::Over.new('foo', 'bar')
4507 ]
4508 assert_equal 1, array.uniq.size
4509 end
4510 array = [
4511 Arel::Nodes::Over.new('foo', 'bar'),
4512 Arel::Nodes::Over.new('foo', 'baz')
4513 ]
4514 assert_equal 2, array.uniq.size
4515 end
4516 end
4517 end
4518 require 'helper'
4519 module Arel
4520 module Nodes
4521 class TestSelectCore Minitest::Test
4522 def test_clone
4523 core = Arel::Nodes::SelectCore.new
4524 core.froms = %w[a b c]
4525 core.projections = %w[d e f]
4526 core.wheres = %w[g h i]
4527 dolly = core.clone
4528 assert_equal core.froms, dolly.froms
4529 assert_equal core.projections, dolly.projections
4530 assert_equal core.wheres, dolly.wheres
4531 refute_same core.froms, dolly.froms
4532 refute_same core.projections, dolly.projections
4533 refute_same core.wheres, dolly.wheres
4534 end
4535 def test_set_quantifier
4536 core = Arel::Nodes::SelectCore.new
4537 core.set_quantifier = Arel::Nodes::Distinct.new
4538 end
4539 def test_equality_with_same_ivars
4540 core1 = SelectCore.new
4541 core1.froms = %w[a b c]
4542 core1.projections = %w[d e f]
4543 core1.wheres = %w[g h i]
4544 core1.groups = %w[j k l]
4545 core1.windows = %w[m n o]
4546 core1.havings = %w[p q r]
4547 core2 = SelectCore.new
4548 core2.froms = %w[a b c]
4549 core2.projections = %w[d e f]
4550 core2.wheres = %w[g h i]
4551 core2.groups = %w[j k l]
4552 core2.windows = %w[m n o]
4553 core2.havings = %w[p q r]
4554 array = [core1, core2]
4555 assert_equal 1, array.uniq.size
4556 end
4557 def test_inequality_with_different_ivars
4558 core1 = SelectCore.new
4559 core1.froms = %w[a b c]
4560 core1.projections = %w[d e f]
4561 core1.wheres = %w[g h i]
4562 core1.groups = %w[j k l]
4563 core1.windows = %w[m n o]
4564 core1.havings = %w[p q r]
4565 core2 = SelectCore.new
4566 core2.froms = %w[a b c]
4567 core2.projections = %w[d e f]
4568 core2.wheres = %w[g h i]
4569 core2.groups = %w[j k l]
4570 core2.windows = %w[m n o]
4571 core2.havings = %w[l o l]
4572 array = [core1, core2]
4573 assert_equal 2, array.uniq.size
4574 end
4575 end
4576 end
4577 end
4578 require 'helper'
4579 describe Arel::Nodes::SelectStatement do
4580 describe "#clone" do
4581 dolly = statement.clone
4582 dolly.cores.must_equal statement.cores
4583 dolly.cores.wont_be_same_as statement.cores
4584 end
4585 end
4586 describe 'equality' do
4587 statement1.offset = 1
4588 statement1.limit = 2
4589 statement1.lock = false
4590 statement1.orders = %w[x y z]
4591 statement1.with = 'zomg'
4592 statement2.offset = 1
4593 statement2.limit = 2
4594 statement2.lock = false
4595 statement2.orders = %w[x y z]
4596 statement2.with = 'zomg'
4597 array = [statement1, statement2]
4598 assert_equal 1, array.uniq.size
4599 end
4600 statement1.offset = 1
4601 statement1.limit = 2
4602 statement1.lock = false
4603 statement1.orders = %w[x y z]
4604 statement1.with = 'zomg'
4605 statement2.offset = 1
4606 statement2.limit = 2
4607 statement2.lock = false
4608 statement2.orders = %w[x y z]
4609 statement2.with = 'wth'
4610 array = [statement1, statement2]
4611 assert_equal 2, array.uniq.size
4612 end
4613 end
4614 end
4615 require 'helper'
4616 require 'yaml'
4617 module Arel
4618 module Nodes
4619 describe 'sql literal' do
4620 before do
4621 end
4622 def compile node
4623 end
4624 describe 'sql' do
4625 sql = Arel.sql 'foo'
4626 sql.must_be_kind_of Arel::Nodes::SqlLiteral
4627 end
4628 end
4629 describe 'count' do
4630 node = SqlLiteral.new('*').count
4631 compile(node).must_be_like %{ COUNT(*) }
4632 end
4633 node = SqlLiteral.new('*').count true
4634 compile(node).must_be_like %{ COUNT(DISTINCT *) }
4635 end
4636 end
4637 describe 'equality' do
4638 node = SqlLiteral.new('foo').eq(1)
4639 compile(node).must_be_like %{ foo = 1 }
4640 end
4641 assert_equal 1, array.uniq.size
4642 end
4643 assert_equal 2, array.uniq.size
4644 end
4645 end
4646 describe 'grouped "or" equality' do
4647 node = SqlLiteral.new('foo').eq_any([1,2])
4648 end
4649 end
4650 describe 'grouped "and" equality' do
4651 node = SqlLiteral.new('foo').eq_all([1,2])
4652 end
4653 end
4654 describe 'serialization' do
4655 yaml_literal = SqlLiteral.new('foo').to_yaml
4656 assert_equal('foo', YAML.load(yaml_literal))
4657 end
4658 end
4659 end
4660 end
4661 end
4662 require 'helper'
4663 describe Arel::Nodes::Sum do
4664 describe "as" do
4665 table = Arel::Table.new :users
4666 table[:id].sum.as('foo').to_sql.must_be_like %{
4667 SUM("users"."id") AS foo
4668 }
4669 end
4670 end
4671 describe 'equality' do
4672 assert_equal 1, array.uniq.size
4673 end
4674 assert_equal 2, array.uniq.size
4675 end
4676 end
4677 end
4678 require 'helper'
4679 require 'ostruct'
4680 module Arel
4681 module Nodes
4682 describe 'table alias' do
4683 describe 'equality' do
4684 relation1 = Table.new(:users)
4685 node1 = TableAlias.new relation1, :foo
4686 relation2 = Table.new(:users)
4687 node2 = TableAlias.new relation2, :foo
4688 array = [node1, node2]
4689 assert_equal 1, array.uniq.size
4690 end
4691 relation1 = Table.new(:users)
4692 node1 = TableAlias.new relation1, :foo
4693 relation2 = Table.new(:users)
4694 node2 = TableAlias.new relation2, :bar
4695 array = [node1, node2]
4696 assert_equal 2, array.uniq.size
4697 end
4698 end
4699 end
4700 end
4701 end
4702 require 'helper'
4703 module Arel
4704 module Nodes
4705 describe 'True' do
4706 describe 'equality' do
4707 array = [True.new, True.new]
4708 assert_equal 1, array.uniq.size
4709 end
4710 array = [True.new, Node.new]
4711 assert_equal 2, array.uniq.size
4712 end
4713 end
4714 end
4715 end
4716 end
4717 require 'helper'
4718 describe Arel::Nodes::UpdateStatement do
4719 describe "#clone" do
4720 statement = Arel::Nodes::UpdateStatement.new
4721 statement.wheres = %w[a b c]
4722 statement.values = %w[x y z]
4723 dolly = statement.clone
4724 dolly.wheres.must_equal statement.wheres
4725 dolly.wheres.wont_be_same_as statement.wheres
4726 dolly.values.must_equal statement.values
4727 dolly.values.wont_be_same_as statement.values
4728 end
4729 end
4730 describe 'equality' do
4731 statement1 = Arel::Nodes::UpdateStatement.new
4732 statement1.relation = 'zomg'
4733 statement1.wheres = 2
4734 statement1.values = false
4735 statement1.orders = %w[x y z]
4736 statement1.limit = 42
4737 statement1.key = 'zomg'
4738 statement2 = Arel::Nodes::UpdateStatement.new
4739 statement2.relation = 'zomg'
4740 statement2.wheres = 2
4741 statement2.values = false
4742 statement2.orders = %w[x y z]
4743 statement2.limit = 42
4744 statement2.key = 'zomg'
4745 array = [statement1, statement2]
4746 assert_equal 1, array.uniq.size
4747 end
4748 statement1 = Arel::Nodes::UpdateStatement.new
4749 statement1.relation = 'zomg'
4750 statement1.wheres = 2
4751 statement1.values = false
4752 statement1.orders = %w[x y z]
4753 statement1.limit = 42
4754 statement1.key = 'zomg'
4755 statement2 = Arel::Nodes::UpdateStatement.new
4756 statement2.relation = 'zomg'
4757 statement2.wheres = 2
4758 statement2.values = false
4759 statement2.orders = %w[x y z]
4760 statement2.limit = 42
4761 statement2.key = 'wth'
4762 array = [statement1, statement2]
4763 assert_equal 2, array.uniq.size
4764 end
4765 end
4766 end
4767 require 'helper'
4768 module Arel
4769 module Nodes
4770 describe 'Window' do
4771 describe 'equality' do
4772 window1 = Window.new
4773 window1.orders = [1, 2]
4774 window1.partitions = [1]
4775 window1.frame 3
4776 window2 = Window.new
4777 window2.orders = [1, 2]
4778 window2.partitions = [1]
4779 window2.frame 3
4780 array = [window1, window2]
4781 assert_equal 1, array.uniq.size
4782 end
4783 window1 = Window.new
4784 window1.orders = [1, 2]
4785 window1.partitions = [1]
4786 window1.frame 3
4787 window2 = Window.new
4788 window2.orders = [1, 2]
4789 window1.partitions = [1]
4790 window2.frame 4
4791 array = [window1, window2]
4792 assert_equal 2, array.uniq.size
4793 end
4794 end
4795 end
4796 describe 'NamedWindow' do
4797 describe 'equality' do
4798 window1 = NamedWindow.new 'foo'
4799 window1.orders = [1, 2]
4800 window1.partitions = [1]
4801 window1.frame 3
4802 window2 = NamedWindow.new 'foo'
4803 window2.orders = [1, 2]
4804 window2.partitions = [1]
4805 window2.frame 3
4806 array = [window1, window2]
4807 assert_equal 1, array.uniq.size
4808 end
4809 window1 = NamedWindow.new 'foo'
4810 window1.orders = [1, 2]
4811 window1.partitions = [1]
4812 window1.frame 3
4813 window2 = NamedWindow.new 'bar'
4814 window2.orders = [1, 2]
4815 window2.partitions = [1]
4816 window2.frame 3
4817 array = [window1, window2]
4818 assert_equal 2, array.uniq.size
4819 end
4820 end
4821 end
4822 describe 'CurrentRow' do
4823 describe 'equality' do
4824 array = [CurrentRow.new, CurrentRow.new]
4825 assert_equal 1, array.uniq.size
4826 end
4827 array = [CurrentRow.new, Node.new]
4828 assert_equal 2, array.uniq.size
4829 end
4830 end
4831 end
4832 end
4833 endmodule FakeRecord
4834 class Column Struct.new(:name, :type)
4835 end
4836 class Connection
4837 attr_reader :tables
4838 attr_accessor :visitor
4839 def initialize(visitor = nil)
4840 @tables = %w{ users photos developers products}
4841 @columns = {
4842 'users' = [
4843 Column.new('id', :integer),
4844 Column.new('name', :string),
4845 Column.new('bool', :boolean),
4846 Column.new('created_at', :date)
4847 ],
4848 'products' = [
4849 Column.new('id', :integer),
4850 Column.new('price', :decimal)
4851 ]
4852 }
4853 @columns_hash = {
4854 }
4855 @primary_keys = {
4856 'users' = 'id',
4857 'products' = 'id'
4858 }
4859 @visitor = visitor
4860 end
4861 def columns_hash table_name
4862 @columns_hash[table_name]
4863 end
4864 def primary_key name
4865 @primary_keys[name.to_s]
4866 end
4867 def table_exists? name
4868 @tables.include? name.to_s
4869 end
4870 def columns name, message = nil
4871 @columns[name.to_s]
4872 end
4873 def quote_table_name name
4874 "\"#{name.to_s}\""
4875 end
4876 def quote_column_name name
4877 "\"#{name.to_s}\""
4878 end
4879 def schema_cache
4880 self
4881 end
4882 def quote thing, column = nil
4883 if column && !thing.nil?
4884 case column.type
4885 when :integer
4886 thing = thing.to_i
4887 when :string
4888 thing = thing.to_s
4889 end
4890 end
4891 case thing
4892 when DateTime
4893 "'#{thing.strftime("%Y-%m-%d %H:%M:%S")}'"
4894 when Date
4895 "'#{thing.strftime("%Y-%m-%d")}'"
4896 when true
4897 "'t'"
4898 when false
4899 "'f'"
4900 when nil
4901 'NULL'
4902 when Numeric
4903 thing
4904 else
4905 "'#{thing.to_s.gsub("'", "\\\\'")}'"
4906 end
4907 end
4908 end
4909 class ConnectionPool
4910 class Spec Struct.new(:config)
4911 end
4912 attr_reader :spec, :connection
4913 def initialize
4914 @spec = Spec.new(:adapter = 'america')
4915 @connection = Connection.new
4916 end
4917 def with_connection
4918 yield connection
4919 end
4920 def table_exists? name
4921 connection.tables.include? name.to_s
4922 end
4923 def columns_hash
4924 connection.columns_hash
4925 end
4926 def schema_cache
4927 connection
4928 end
4929 def quote thing, column = nil
4930 connection.quote thing, column
4931 end
4932 end
4933 class Base
4934 attr_accessor :connection_pool
4935 def initialize
4936 @connection_pool = ConnectionPool.new
4937 end
4938 def connection
4939 connection_pool.connection
4940 end
4941 end
4942 end
4943 require 'helper'
4944 module Arel
4945 describe 'Attributes' do
4946 relation = Table.new(:users)
4947 attribute = relation[:foo]
4948 node = attribute.lower
4949 assert_equal 'LOWER', node.name
4950 assert_equal [attribute], node.expressions
4951 end
4952 describe 'equality' do
4953 assert_equal 1, array.uniq.size
4954 end
4955 assert_equal 2, array.uniq.size
4956 end
4957 end
4958 describe 'for' do
4959 column = Struct.new(:type).new :crazy
4960 end
4961 [:string, :text, :binary].each do |type|
4962 column = Struct.new(:type).new type
4963 end
4964 end
4965 column = Struct.new(:type).new :integer
4966 end
4967 column = Struct.new(:type).new :float
4968 end
4969 column = Struct.new(:type).new :decimal
4970 end
4971 column = Struct.new(:type).new :boolean
4972 end
4973 column = Struct.new(:type).new type
4974 end
4975 end
4976 end
4977 end
4978 end
4979 require 'helper'
4980 module Arel
4981 class FakeCrudder SelectManager
4982 class FakeEngine
4983 def initialize
4984 @calls = []
4985 @connection_pool = self
4986 @spec = self
4987 @config = { :adapter = 'sqlite3' }
4988 end
4989 def connection; self end
4990 def method_missing name, *args
4991 @calls [name, args]
4992 end
4993 end
4994 include Crud
4995 attr_reader :engine
4996 attr_accessor :ctx
4997 def initialize engine = FakeEngine.new
4998 super
4999 end
5000 end
5001 describe 'crud' do
5002 describe 'insert' do
5003 table = Table.new :users
5004 fc = FakeCrudder.new
5005 fc.from table
5006 im = fc.compile_insert [[table[:id], 'foo']]
5007 assert_instance_of Arel::InsertManager, im
5008 end
5009 end
5010 describe 'update' do
5011 table = Table.new :users
5012 fc = FakeCrudder.new
5013 fc.from table
5014 assert_instance_of Arel::UpdateManager, stmt
5015 end
5016 end
5017 describe 'delete' do
5018 table = Table.new :users
5019 fc = FakeCrudder.new
5020 fc.from table
5021 stmt = fc.compile_delete
5022 assert_instance_of Arel::DeleteManager, stmt
5023 end
5024 end
5025 end
5026 end
5027 require 'helper'
5028 module Arel
5029 describe 'delete manager' do
5030 describe 'new' do
5031 Arel::DeleteManager.new
5032 end
5033 end
5034 describe 'from' do
5035 table = Table.new(:users)
5036 dm = Arel::DeleteManager.new
5037 dm.from table
5038 dm.to_sql.must_be_like %{ DELETE FROM "users" }
5039 end
5040 table = Table.new(:users)
5041 dm = Arel::DeleteManager.new
5042 dm.from(table).must_equal dm
5043 end
5044 end
5045 describe 'where' do
5046 table = Table.new(:users)
5047 dm = Arel::DeleteManager.new
5048 dm.from table
5049 dm.where table[:id].eq(10)
5050 end
5051 table = Table.new(:users)
5052 dm = Arel::DeleteManager.new
5053 dm.where(table[:id].eq(10)).must_equal dm
5054 end
5055 end
5056 end
5057 end
5058 require 'helper'
5059 module Arel
5060 module FactoryMethods
5061 class TestFactoryMethods Minitest::Test
5062 class Factory
5063 include Arel::FactoryMethods
5064 end
5065 def setup
5066 @factory = Factory.new
5067 end
5068 def test_create_join
5069 join = @factory.create_join :one, :two
5070 assert_kind_of Nodes::Join, join
5071 assert_equal :two, join.right
5072 end
5073 def test_create_on
5074 on = @factory.create_on :one
5075 assert_instance_of Nodes::On, on
5076 assert_equal :one, on.expr
5077 end
5078 def test_create_true
5079 true_node = @factory.create_true
5080 assert_instance_of Nodes::True, true_node
5081 end
5082 def test_create_false
5083 false_node = @factory.create_false
5084 assert_instance_of Nodes::False, false_node
5085 end
5086 def test_lower
5087 lower = @factory.lower :one
5088 assert_instance_of Nodes::NamedFunction, lower
5089 assert_equal 'LOWER', lower.name
5090 end
5091 end
5092 end
5093 end
5094 require 'helper'
5095 module Arel
5096 describe 'insert manager' do
5097 describe 'new' do
5098 Arel::InsertManager.new
5099 end
5100 end
5101 describe 'insert' do
5102 manager = Arel::InsertManager.new
5103 assert_kind_of Arel::Nodes::Values, values
5104 assert_equal %w{ a b }, values.left
5105 assert_equal %w{ c d }, values.right
5106 end
5107 manager = Arel::InsertManager.new
5108 manager.into Table.new(:users)
5109 manager.to_sql.must_be_like %{
5110 INSERT INTO \"users\" VALUES (*)
5111 }
5112 end
5113 table = Table.new(:users)
5114 manager = Arel::InsertManager.new
5115 manager.insert [[table[:bool], false]]
5116 manager.to_sql.must_be_like %{
5117 INSERT INTO "users" ("bool") VALUES ('f')
5118 }
5119 end
5120 table = Table.new(:users)
5121 manager = Arel::InsertManager.new
5122 manager.insert [[table[:id], nil]]
5123 manager.to_sql.must_be_like %{
5124 INSERT INTO "users" ("id") VALUES (NULL)
5125 }
5126 end
5127 table = Table.new(:users)
5128 manager = Arel::InsertManager.new
5129 time = Time.now
5130 attribute = table[:created_at]
5131 manager.insert [[attribute, time]]
5132 manager.to_sql.must_be_like %{
5133 }
5134 end
5135 table = Table.new(:users)
5136 manager = Arel::InsertManager.new
5137 manager.into table
5138 manager.to_sql.must_be_like %{
5139 }
5140 end
5141 table = Table.new(:users)
5142 manager = Arel::InsertManager.new
5143 manager.to_sql.must_be_like %{
5144 }
5145 end
5146 table = Table.new(:users)
5147 manager = Arel::InsertManager.new
5148 manager.insert [[table[:id], 1]]
5149 manager.insert []
5150 manager.to_sql.must_be_like %{
5151 INSERT INTO "users" ("id") VALUES (1)
5152 }
5153 end
5154 end
5155 describe 'into' do
5156 manager = Arel::InsertManager.new
5157 end
5158 table = Table.new :users
5159 manager = Arel::InsertManager.new
5160 manager.into table
5161 manager.to_sql.must_be_like %{
5162 INSERT INTO "users"
5163 }
5164 end
5165 end
5166 describe 'columns' do
5167 table = Table.new :users
5168 manager = Arel::InsertManager.new
5169 manager.into table
5170 manager.columns table[:id]
5171 manager.to_sql.must_be_like %{
5172 INSERT INTO "users" ("id")
5173 }
5174 end
5175 end
5176 describe "values" do
5177 table = Table.new :users
5178 manager = Arel::InsertManager.new
5179 manager.into table
5180 manager.values = Nodes::Values.new [1]
5181 manager.to_sql.must_be_like %{
5182 INSERT INTO "users" VALUES (1)
5183 }
5184 end
5185 end
5186 describe "combo" do
5187 table = Table.new :users
5188 manager = Arel::InsertManager.new
5189 manager.into table
5190 manager.values = Nodes::Values.new [1, 'aaron']
5191 manager.columns table[:id]
5192 manager.columns table[:name]
5193 manager.to_sql.must_be_like %{
5194 }
5195 end
5196 end
5197 describe "select" do
5198 table = Table.new :users
5199 manager = Arel::InsertManager.new
5200 manager.into table
5201 select = Arel::SelectManager.new
5202 select.project Arel.sql('1')
5203 select.project Arel.sql('"aaron"')
5204 manager.select select
5205 manager.columns table[:id]
5206 manager.columns table[:name]
5207 manager.to_sql.must_be_like %{
5208 }
5209 end
5210 end
5211 end
5212 end
5213 require 'helper'
5214 module Arel
5215 describe 'select manager' do
5216 def test_join_sources
5217 manager = Arel::SelectManager.new
5218 assert_equal "SELECT FROM 'foo'", manager.to_sql
5219 end
5220 def test_manager_stores_bind_values
5221 manager = Arel::SelectManager.new
5222 assert_equal [], manager.bind_values
5223 manager.bind_values = [1]
5224 assert_equal [1], manager.bind_values
5225 end
5226 describe 'backwards compatibility' do
5227 describe 'project' do
5228 table = Table.new :users
5229 manager = Arel::SelectManager.new
5230 manager.project :id
5231 manager.from table
5232 manager.to_sql.must_be_like %{
5233 SELECT id FROM "users"
5234 }
5235 end
5236 end
5237 describe 'order' do
5238 table = Table.new :users
5239 manager = Arel::SelectManager.new
5240 manager.project Nodes::SqlLiteral.new '*'
5241 manager.from table
5242 manager.order :foo
5243 end
5244 end
5245 describe 'group' do
5246 table = Table.new :users
5247 manager = Arel::SelectManager.new
5248 manager.from table
5249 manager.group :foo
5250 end
5251 end
5252 describe 'as' do
5253 manager = Arel::SelectManager.new
5254 as = manager.as(Arel.sql('foo'))
5255 assert_kind_of Arel::Nodes::Grouping, as.left
5256 assert_equal manager.ast, as.left.expr
5257 assert_equal 'foo', as.right
5258 end
5259 manager = Arel::SelectManager.new
5260 as = manager.as('foo')
5261 assert_kind_of Arel::Nodes::SqlLiteral, as.right
5262 end
5263 manager = Arel::SelectManager.new
5264 manager.project Arel.star
5265 manager.from Arel.sql('zomg')
5266 as = manager.as(Arel.sql('foo'))
5267 manager = Arel::SelectManager.new
5268 manager.project Arel.sql('name')
5269 manager.from as
5270 end
5271 end
5272 describe 'from' do
5273 table = Table.new :users
5274 manager = Arel::SelectManager.new
5275 manager.from table
5276 manager.from 'users'
5277 manager.project table['id']
5278 end
5279 table = Table.new :users
5280 manager1 = Arel::SelectManager.new
5281 manager2 = Arel::SelectManager.new
5282 manager2.project(Arel.sql('*'))
5283 manager2.from table
5284 manager1.project Arel.sql('lol')
5285 as = manager2.as Arel.sql('omg')
5286 manager1.from(as)
5287 manager1.to_sql.must_be_like %{
5288 SELECT lol FROM (SELECT * FROM "users") omg
5289 }
5290 end
5291 end
5292 describe 'having' do
5293 table = Table.new :users
5294 mgr = table.from
5295 mgr.having Arel.sql('foo')
5296 end
5297 table = Table.new :users
5298 mgr = table.from
5299 mgr.having Arel.sql('foo')
5300 mgr.having Arel.sql('bar')
5301 end
5302 table = Table.new :users
5303 mgr = table.from
5304 end
5305 end
5306 describe 'on' do
5307 table = Table.new :users
5308 right = table.alias
5309 mgr = table.from
5310 mgr.join(right).on("omg")
5311 end
5312 table = Table.new :users
5313 right = table.alias
5314 mgr = table.from
5315 mgr.join(right).on("omg", "123")
5316 end
5317 end
5318 end
5319 describe 'clone' do
5320 table = Table.new :users, :as = 'foo'
5321 mgr = table.from
5322 m2 = mgr.clone
5323 m2.project "foo"
5324 mgr.to_sql.wont_equal m2.to_sql
5325 end
5326 table = Table.new :users, :as = 'foo'
5327 mgr = table.from
5328 m2 = mgr.clone
5329 m3 = m2.clone
5330 m2.project "foo"
5331 mgr.to_sql.wont_equal m2.to_sql
5332 m3.to_sql.must_equal mgr.to_sql
5333 end
5334 end
5335 describe 'initialize' do
5336 table = Table.new :users, :as = 'foo'
5337 mgr = table.from
5338 mgr.skip 10
5339 end
5340 end
5341 describe 'skip' do
5342 table = Table.new :users
5343 mgr = table.from
5344 mgr.skip 10
5345 end
5346 table = Table.new :users
5347 mgr = table.from
5348 end
5349 end
5350 describe 'offset' do
5351 table = Table.new :users
5352 mgr = table.from
5353 mgr.offset = 10
5354 end
5355 table = Table.new :users
5356 mgr = table.from
5357 mgr.offset = 10
5358 mgr.offset = nil
5359 mgr.to_sql.must_be_like %{ SELECT FROM "users" }
5360 end
5361 table = Table.new :users
5362 mgr = table.from
5363 mgr.offset = 10
5364 assert_equal 10, mgr.offset
5365 end
5366 end
5367 describe 'exists' do
5368 table = Table.new(:users)
5369 manager = Arel::SelectManager.new table
5370 manager.project Nodes::SqlLiteral.new '*'
5371 m2 = Arel::SelectManager.new(manager.engine)
5372 m2.project manager.exists
5373 end
5374 table = Table.new(:users)
5375 manager = Arel::SelectManager.new table
5376 manager.project Nodes::SqlLiteral.new '*'
5377 m2 = Arel::SelectManager.new(manager.engine)
5378 m2.project manager.exists.as('foo')
5379 end
5380 end
5381 describe 'union' do
5382 before do
5383 table = Table.new :users
5384 @m1 = Arel::SelectManager.new table
5385 @m1.project Arel.star
5386 @m1.where(table[:age].lt(18))
5387 @m2 = Arel::SelectManager.new table
5388 @m2.project Arel.star
5389 @m2.where(table[:age].gt(99))
5390 end
5391 node = @m1.union @m2
5392 node.to_sql.must_be_like %{
5393 }
5394 end
5395 node = @m1.union :all, @m2
5396 node.to_sql.must_be_like %{
5397 }
5398 end
5399 end
5400 describe 'intersect' do
5401 before do
5402 table = Table.new :users
5403 @m1 = Arel::SelectManager.new table
5404 @m1.project Arel.star
5405 @m1.where(table[:age].gt(18))
5406 @m2 = Arel::SelectManager.new table
5407 @m2.project Arel.star
5408 @m2.where(table[:age].lt(99))
5409 end
5410 node = @m1.intersect @m2
5411 node.to_sql.must_be_like %{
5412 }
5413 end
5414 end
5415 describe 'except' do
5416 before do
5417 table = Table.new :users
5418 @m1 = Arel::SelectManager.new table
5419 @m1.project Arel.star
5420 @m1.where(table[:age].between(18..60))
5421 @m2 = Arel::SelectManager.new table
5422 @m2.project Arel.star
5423 @m2.where(table[:age].between(40..99))
5424 end
5425 node = @m1.except @m2
5426 node.to_sql.must_be_like %{
5427 }
5428 end
5429 end
5430 describe 'with' do
5431 users = Table.new(:users)
5432 users_top = Table.new(:users_top)
5433 comments = Table.new(:comments)
5434 users_as = Arel::Nodes::As.new(users_top, top)
5435 select_manager.to_sql.must_be_like %{
5436 }
5437 end
5438 comments = Table.new(:comments)
5439 comments_id = comments[:id]
5440 comments_parent_id = comments[:parent_id]
5441 replies = Table.new(:replies)
5442 replies_id = replies[:id]
5443 recursive_term = Arel::SelectManager.new
5444 non_recursive_term = Arel::SelectManager.new
5445 union = recursive_term.union(non_recursive_term)
5446 as_statement = Arel::Nodes::As.new replies, union
5447 manager = Arel::SelectManager.new
5448 sql = manager.to_sql
5449 sql.must_be_like %{
5450 WITH RECURSIVE "replies" AS (
5451 UNION
5452 )
5453 SELECT * FROM "replies"
5454 }
5455 end
5456 end
5457 describe 'ast' do
5458 table = Table.new :users
5459 mgr = table.from
5460 assert mgr.ast
5461 end
5462 table = Table.new :users
5463 mgr = table.from
5464 mgr.project Arel.sql '*'
5465 mgr.from table
5466 mgr.ast.grep(Arel::Nodes::OuterJoin)
5467 end
5468 end
5469 describe 'taken' do
5470 manager = Arel::SelectManager.new
5471 manager.take 10
5472 manager.taken.must_equal 10
5473 end
5474 end
5475 describe 'lock' do
5476 table = Table.new :users
5477 mgr = table.from
5478 end
5479 end
5480 describe 'orders' do
5481 table = Table.new :users
5482 manager = Arel::SelectManager.new
5483 order = table[:id]
5484 manager.order table[:id]
5485 manager.orders.must_equal [order]
5486 end
5487 end
5488 describe 'order' do
5489 table = Table.new :users
5490 manager = Arel::SelectManager.new
5491 manager.project Nodes::SqlLiteral.new '*'
5492 manager.from table
5493 manager.order table[:id]
5494 manager.to_sql.must_be_like %{
5495 SELECT * FROM "users" ORDER BY "users"."id"
5496 }
5497 end
5498 table = Table.new :users
5499 manager = Arel::SelectManager.new
5500 manager.project Nodes::SqlLiteral.new '*'
5501 manager.from table
5502 manager.order table[:id], table[:name]
5503 manager.to_sql.must_be_like %{
5504 }
5505 end
5506 table = Table.new :users
5507 manager = Arel::SelectManager.new
5508 manager.order(table[:id]).must_equal manager
5509 end
5510 table = Table.new :users
5511 manager = Arel::SelectManager.new
5512 manager.project Nodes::SqlLiteral.new '*'
5513 manager.from table
5514 manager.order table[:id].desc
5515 manager.to_sql.must_be_like %{
5516 SELECT * FROM "users" ORDER BY "users"."id" DESC
5517 }
5518 end
5519 end
5520 describe 'on' do
5521 left = Table.new :users
5522 right = left.alias
5523 predicate = left[:id].eq(right[:id])
5524 manager = Arel::SelectManager.new
5525 manager.from left
5526 manager.join(right).on(predicate, predicate)
5527 manager.to_sql.must_be_like %{
5528 SELECT FROM "users"
5529 INNER JOIN "users" "users_2"
5530 ON "users"."id" = "users_2"."id" AND
5531 "users"."id" = "users_2"."id"
5532 }
5533 end
5534 left = Table.new :users
5535 right = left.alias
5536 predicate = left[:id].eq(right[:id])
5537 manager = Arel::SelectManager.new
5538 manager.from left
5539 manager.join(right).on(
5540 predicate,
5541 predicate,
5542 left[:name].eq(right[:name])
5543 )
5544 manager.to_sql.must_be_like %{
5545 SELECT FROM "users"
5546 INNER JOIN "users" "users_2"
5547 ON "users"."id" = "users_2"."id" AND
5548 "users"."id" = "users_2"."id" AND
5549 "users"."name" = "users_2"."name"
5550 }
5551 end
5552 end
5553 relation = Arel::SelectManager.new
5554 assert_equal [], relation.froms
5555 end
5556 relation = Arel::SelectManager.new
5557 children = ['foo', 'bar', 'baz']
5558 clause = relation.create_and children
5559 assert_kind_of Arel::Nodes::And, clause
5560 assert_equal children, clause.children
5561 end
5562 relation = Arel::SelectManager.new
5563 insert = relation.create_insert
5564 assert_kind_of Arel::InsertManager, insert
5565 end
5566 relation = Arel::SelectManager.new
5567 join = relation.create_join 'foo', 'bar'
5568 assert_kind_of Arel::Nodes::InnerJoin, join
5569 assert_equal 'foo', join.left
5570 assert_equal 'bar', join.right
5571 end
5572 relation = Arel::SelectManager.new
5573 assert_kind_of Arel::Nodes::FullOuterJoin, join
5574 assert_equal 'foo', join.left
5575 assert_equal 'bar', join.right
5576 end
5577 relation = Arel::SelectManager.new
5578 assert_kind_of Arel::Nodes::OuterJoin, join
5579 assert_equal 'foo', join.left
5580 assert_equal 'bar', join.right
5581 end
5582 relation = Arel::SelectManager.new
5583 assert_kind_of Arel::Nodes::RightOuterJoin, join
5584 assert_equal 'foo', join.left
5585 assert_equal 'bar', join.right
5586 end
5587 describe 'join' do
5588 left = Table.new :users
5589 right = left.alias
5590 predicate = left[:id].eq(right[:id])
5591 manager = Arel::SelectManager.new
5592 manager.from left
5593 manager.join(right).on(predicate)
5594 manager.to_sql.must_be_like %{
5595 SELECT FROM "users"
5596 INNER JOIN "users" "users_2"
5597 ON "users"."id" = "users_2"."id"
5598 }
5599 end
5600 left = Table.new :users
5601 right = left.alias
5602 predicate = left[:id].eq(right[:id])
5603 manager = Arel::SelectManager.new
5604 manager.from left
5605 manager.to_sql.must_be_like %{
5606 SELECT FROM "users"
5607 LEFT OUTER JOIN "users" "users_2"
5608 ON "users"."id" = "users_2"."id"
5609 }
5610 end
5611 manager = Arel::SelectManager.new
5612 manager.join(nil).must_equal manager
5613 end
5614 end
5615 describe 'outer join' do
5616 left = Table.new :users
5617 right = left.alias
5618 predicate = left[:id].eq(right[:id])
5619 manager = Arel::SelectManager.new
5620 manager.from left
5621 manager.outer_join(right).on(predicate)
5622 manager.to_sql.must_be_like %{
5623 SELECT FROM "users"
5624 LEFT OUTER JOIN "users" "users_2"
5625 ON "users"."id" = "users_2"."id"
5626 }
5627 end
5628 manager = Arel::SelectManager.new
5629 manager.outer_join(nil).must_equal manager
5630 end
5631 end
5632 describe 'joins' do
5633 table = Table.new :users
5634 aliaz = table.alias
5635 manager = Arel::SelectManager.new
5636 manager.to_sql
5637 end
5638 table = Table.new :users
5639 aliaz = table.alias
5640 manager = Arel::SelectManager.new
5641 manager.to_sql
5642 end
5643 users = Table.new :users
5644 comments = Table.new :comments
5645 counts = comments.from.
5646 group(comments[:user_id]).
5647 project(
5648 comments[:user_id].as("user_id"),
5649 comments[:user_id].count.as("count")
5650 ).as("counts")
5651 joins.to_sql.must_be_like %{
5652 }
5653 end
5654 left = Table.new :users
5655 right = left.alias
5656 predicate = left[:id].eq(right[:id])
5657 mgr = left.join(right)
5658 mgr.project Nodes::SqlLiteral.new('*')
5659 mgr.on(predicate).must_equal mgr
5660 mgr.to_sql.must_be_like %{
5661 SELECT * FROM "users"
5662 INNER JOIN "users" "users_2"
5663 ON "users"."id" = "users_2"."id"
5664 }
5665 end
5666 manager = Arel::SelectManager.new
5667 assert_match "'hello'", manager.to_sql
5668 end
5669 end
5670 describe 'group' do
5671 table = Table.new :users
5672 manager = Arel::SelectManager.new
5673 manager.from table
5674 manager.group table[:id]
5675 manager.to_sql.must_be_like %{
5676 SELECT FROM "users" GROUP BY "users"."id"
5677 }
5678 end
5679 table = Table.new :users
5680 manager = Arel::SelectManager.new
5681 manager.group(table[:id]).must_equal manager
5682 end
5683 table = Table.new :users
5684 manager = Arel::SelectManager.new
5685 manager.from table
5686 manager.group table[:id], table[:name]
5687 manager.to_sql.must_be_like %{
5688 }
5689 end
5690 table = Table.new :users
5691 manager = Arel::SelectManager.new
5692 manager.from table
5693 manager.group 'foo'
5694 end
5695 end
5696 describe 'window definition' do
5697 table = Table.new :users
5698 manager = Arel::SelectManager.new
5699 manager.from table
5700 manager.window('a_window')
5701 manager.to_sql.must_be_like %{
5702 SELECT FROM "users" WINDOW "a_window" AS ()
5703 }
5704 end
5705 table = Table.new :users
5706 manager = Arel::SelectManager.new
5707 manager.from table
5708 manager.to_sql.must_be_like %{
5709 }
5710 end
5711 table = Table.new :users
5712 manager = Arel::SelectManager.new
5713 manager.from table
5714 manager.to_sql.must_be_like %{
5715 }
5716 end
5717 table = Table.new :users
5718 manager = Arel::SelectManager.new
5719 manager.from table
5720 manager.to_sql.must_be_like %{
5721 }
5722 end
5723 table = Table.new :users
5724 manager = Arel::SelectManager.new
5725 manager.from table
5726 manager.to_sql.must_be_like %{
5727 ORDER BY "users"."foo" ASC)
5728 }
5729 end
5730 table = Table.new :users
5731 manager = Arel::SelectManager.new
5732 manager.from table
5733 manager.to_sql.must_be_like %{
5734 }
5735 end
5736 table = Table.new :users
5737 manager = Arel::SelectManager.new
5738 manager.from table
5739 manager.to_sql.must_be_like %{
5740 }
5741 end
5742 table = Table.new :users
5743 manager = Arel::SelectManager.new
5744 manager.from table
5745 manager.to_sql.must_be_like %{
5746 }
5747 end
5748 table = Table.new :users
5749 manager = Arel::SelectManager.new
5750 manager.from table
5751 manager.to_sql.must_be_like %{
5752 }
5753 end
5754 table = Table.new :users
5755 manager = Arel::SelectManager.new
5756 manager.from table
5757 manager.to_sql.must_be_like %{
5758 }
5759 end
5760 table = Table.new :users
5761 manager = Arel::SelectManager.new
5762 manager.from table
5763 manager.to_sql.must_be_like %{
5764 }
5765 end
5766 table = Table.new :users
5767 manager = Arel::SelectManager.new
5768 manager.from table
5769 window = manager.window('a_window')
5770 window.frame(
5771 Arel::Nodes::Between.new(
5772 window.rows,
5773 Nodes::And.new([
5774 Arel::Nodes::Preceding.new,
5775 Arel::Nodes::CurrentRow.new
5776 ])))
5777 manager.to_sql.must_be_like %{
5778 }
5779 end
5780 table = Table.new :users
5781 manager = Arel::SelectManager.new
5782 manager.from table
5783 manager.to_sql.must_be_like %{
5784 }
5785 end
5786 table = Table.new :users
5787 manager = Arel::SelectManager.new
5788 manager.from table
5789 manager.to_sql.must_be_like %{
5790 }
5791 end
5792 table = Table.new :users
5793 manager = Arel::SelectManager.new
5794 manager.from table
5795 manager.to_sql.must_be_like %{
5796 }
5797 end
5798 table = Table.new :users
5799 manager = Arel::SelectManager.new
5800 manager.from table
5801 manager.to_sql.must_be_like %{
5802 }
5803 end
5804 table = Table.new :users
5805 manager = Arel::SelectManager.new
5806 manager.from table
5807 manager.to_sql.must_be_like %{
5808 }
5809 end
5810 table = Table.new :users
5811 manager = Arel::SelectManager.new
5812 manager.from table
5813 window = manager.window('a_window')
5814 window.frame(
5815 Arel::Nodes::Between.new(
5816 window.range,
5817 Nodes::And.new([
5818 Arel::Nodes::Preceding.new,
5819 Arel::Nodes::CurrentRow.new
5820 ])))
5821 manager.to_sql.must_be_like %{
5822 }
5823 end
5824 end
5825 describe 'delete' do
5826 table = Table.new :users
5827 manager = Arel::SelectManager.new
5828 manager.from table
5829 stmt = manager.compile_delete
5830 stmt.to_sql.must_be_like %{ DELETE FROM "users" }
5831 end
5832 table = Table.new :users
5833 manager = Arel::SelectManager.new
5834 manager.from table
5835 manager.where table[:id].eq 10
5836 stmt = manager.compile_delete
5837 stmt.to_sql.must_be_like %{
5838 DELETE FROM "users" WHERE "users"."id" = 10
5839 }
5840 end
5841 end
5842 describe 'where_sql' do
5843 table = Table.new :users
5844 manager = Arel::SelectManager.new
5845 manager.from table
5846 manager.where table[:id].eq 10
5847 end
5848 table = Table.new :users
5849 manager = Arel::SelectManager.new
5850 manager.from table
5851 manager.where_sql.must_be_nil
5852 end
5853 end
5854 describe 'update' do
5855 table = Table.new :users
5856 manager = Arel::SelectManager.new
5857 manager.from table
5858 stmt.to_sql.must_be_like %{
5859 UPDATE "users" SET "id" = 1
5860 }
5861 end
5862 table = Table.new :users
5863 manager = Arel::SelectManager.new
5864 manager.from table
5865 end
5866 table = Table.new :users
5867 manager = Arel::SelectManager.new
5868 manager.from table
5869 manager.take 1
5870 stmt.key = table['id']
5871 stmt.to_sql.must_be_like %{
5872 UPDATE "users" SET foo = bar
5873 }
5874 end
5875 table = Table.new :users
5876 manager = Arel::SelectManager.new
5877 manager.from table
5878 manager.order :foo
5879 stmt.key = table['id']
5880 stmt.to_sql.must_be_like %{
5881 UPDATE "users" SET foo = bar
5882 }
5883 end
5884 table = Table.new :users
5885 manager = Arel::SelectManager.new
5886 manager.where table[:id].eq 10
5887 manager.from table
5888 stmt.to_sql.must_be_like %{
5889 }
5890 end
5891 table = Table.new :users
5892 manager = Arel::SelectManager.new
5893 manager.where table[:foo].eq 10
5894 manager.take 42
5895 manager.from table
5896 stmt.to_sql.must_be_like %{
5897 }
5898 end
5899 end
5900 describe 'project' do
5901 manager = Arel::SelectManager.new
5902 manager.project Nodes::SqlLiteral.new '*'
5903 manager.to_sql.must_be_like %{ SELECT * }
5904 end
5905 manager = Arel::SelectManager.new
5906 manager.project Nodes::SqlLiteral.new('foo'),
5907 Nodes::SqlLiteral.new('bar')
5908 manager.to_sql.must_be_like %{ SELECT foo, bar }
5909 end
5910 manager = Arel::SelectManager.new
5911 manager.project '*'
5912 manager.to_sql.must_be_like %{ SELECT * }
5913 end
5914 end
5915 describe 'projections' do
5916 manager = Arel::SelectManager.new
5917 manager.project Arel.sql('foo'), Arel.sql('bar')
5918 end
5919 end
5920 describe 'projections=' do
5921 manager = Arel::SelectManager.new
5922 manager.project Arel.sql('foo')
5923 manager.projections = [Arel.sql('bar')]
5924 manager.to_sql.must_be_like %{ SELECT bar }
5925 end
5926 end
5927 describe 'take' do
5928 table = Table.new :users
5929 manager = Arel::SelectManager.new
5930 manager.from(table).project(table['id'])
5931 manager.where(table['id'].eq(1))
5932 manager.take 1
5933 manager.to_sql.must_be_like %{
5934 SELECT "users"."id"
5935 FROM "users"
5936 WHERE "users"."id" = 1
5937 LIMIT 1
5938 }
5939 end
5940 manager = Arel::SelectManager.new
5941 manager.take(1).must_equal manager
5942 end
5943 manager = Arel::SelectManager.new
5944 manager.limit = 10
5945 assert_match('LIMIT', manager.to_sql)
5946 manager.limit = nil
5947 refute_match('LIMIT', manager.to_sql)
5948 end
5949 end
5950 describe 'where' do
5951 table = Table.new :users
5952 manager = Arel::SelectManager.new
5953 manager.from(table).project(table['id'])
5954 manager.where(table['id'].eq(1))
5955 manager.to_sql.must_be_like %{
5956 SELECT "users"."id"
5957 FROM "users"
5958 WHERE "users"."id" = 1
5959 }
5960 end
5961 table = Table.new :users
5962 manager = Arel::SelectManager.new
5963 manager.from(table)
5964 end
5965 end
5966 describe 'from' do
5967 table = Table.new :users
5968 manager = Arel::SelectManager.new
5969 manager.from table
5970 manager.project table['id']
5971 end
5972 table = Table.new :users
5973 manager = Arel::SelectManager.new
5974 end
5975 end
5976 describe 'source' do
5977 manager = Arel::SelectManager.new
5978 end
5979 end
5980 describe 'distinct' do
5981 manager = Arel::SelectManager.new
5982 manager.distinct
5983 manager.distinct(false)
5984 end
5985 manager = Arel::SelectManager.new
5986 manager.distinct.must_equal manager
5987 manager.distinct(false).must_equal manager
5988 end
5989 end
5990 describe 'distinct_on' do
5991 manager = Arel::SelectManager.new
5992 table = Table.new :users
5993 manager.distinct_on(table['id'])
5994 manager.distinct_on(false)
5995 end
5996 manager = Arel::SelectManager.new
5997 table = Table.new :users
5998 manager.distinct_on(false).must_equal manager
5999 end
6000 end
6001 end
6002 end
6003 require 'helper'
6004 module Arel
6005 describe Table do
6006 before do
6007 @relation = Table.new(:users)
6008 end
6009 join = @relation.create_string_join 'foo'
6010 assert_kind_of Arel::Nodes::StringJoin, join
6011 assert_equal 'foo', join.left
6012 end
6013 join = @relation.create_join 'foo', 'bar'
6014 assert_kind_of Arel::Nodes::InnerJoin, join
6015 assert_equal 'foo', join.left
6016 assert_equal 'bar', join.right
6017 end
6018 assert_kind_of Arel::Nodes::FullOuterJoin, join
6019 assert_equal 'foo', join.left
6020 assert_equal 'bar', join.right
6021 end
6022 assert_kind_of Arel::Nodes::OuterJoin, join
6023 assert_equal 'foo', join.left
6024 assert_equal 'bar', join.right
6025 end
6026 assert_kind_of Arel::Nodes::RightOuterJoin, join
6027 assert_equal 'foo', join.left
6028 assert_equal 'bar', join.right
6029 end
6030 im = @relation.compile_insert 'VALUES(NULL)'
6031 assert_kind_of Arel::InsertManager, im
6032 im.into Table.new(:users)
6033 end
6034 describe 'skip' do
6035 sm = @relation.skip 2
6036 end
6037 end
6038 describe 'having' do
6039 mgr = @relation.having @relation[:id].eq(10)
6040 mgr.to_sql.must_be_like %{
6041 SELECT FROM "users" HAVING "users"."id" = 10
6042 }
6043 end
6044 end
6045 describe 'backwards compat' do
6046 describe 'join' do
6047 mgr = @relation.join nil
6048 mgr.to_sql.must_be_like %{ SELECT FROM "users" }
6049 end
6050 right = @relation.alias
6051 predicate = @relation[:id].eq(right[:id])
6052 mgr.to_sql.must_be_like %{
6053 SELECT FROM "users"
6054 LEFT OUTER JOIN "users" "users_2"
6055 ON "users"."id" = "users_2"."id"
6056 }
6057 end
6058 end
6059 describe 'join' do
6060 right = @relation.alias
6061 predicate = @relation[:id].eq(right[:id])
6062 mgr = @relation.outer_join(right).on(predicate)
6063 mgr.to_sql.must_be_like %{
6064 SELECT FROM "users"
6065 LEFT OUTER JOIN "users" "users_2"
6066 ON "users"."id" = "users_2"."id"
6067 }
6068 end
6069 end
6070 end
6071 describe 'group' do
6072 manager = @relation.group @relation[:id]
6073 manager.to_sql.must_be_like %{
6074 SELECT FROM "users" GROUP BY "users"."id"
6075 }
6076 end
6077 end
6078 describe 'alias' do
6079 @relation.aliases.must_equal []
6080 node = @relation.alias
6081 @relation.aliases.must_equal [node]
6082 node.name.must_equal 'users_2'
6083 node[:id].relation.must_equal node
6084 end
6085 end
6086 describe 'new' do
6087 rel = Table.new :users, :as = 'foo'
6088 rel.table_alias.must_equal 'foo'
6089 end
6090 rel = Table.new :users, :as = 'users'
6091 rel.table_alias.must_be_nil
6092 end
6093 end
6094 describe 'order' do
6095 manager = @relation.order "foo"
6096 end
6097 end
6098 describe 'take' do
6099 manager = @relation.take 1
6100 manager.project Nodes::SqlLiteral.new '*'
6101 end
6102 end
6103 describe 'project' do
6104 end
6105 end
6106 end
6107 describe 'where' do
6108 manager = @relation.where @relation[:id].eq 1
6109 manager.project @relation[:id]
6110 manager.must_be_kind_of TreeManager
6111 manager.to_sql.must_be_like %{
6112 SELECT "users"."id"
6113 FROM "users"
6114 WHERE "users"."id" = 1
6115 }
6116 end
6117 end
6118 @relation.name.must_equal 'users'
6119 end
6120 @relation.table_name.must_equal 'users'
6121 end
6122 describe '[]' do
6123 describe 'when given a Symbol' do
6124 column = @relation[:id]
6125 column.name.must_equal :id
6126 end
6127 end
6128 end
6129 describe 'equality' do
6130 relation1 = Table.new(:users)
6131 relation1.aliases = %w[a b c]
6132 relation1.table_alias = 'zomg'
6133 relation2 = Table.new(:users)
6134 relation2.aliases = %w[a b c]
6135 relation2.table_alias = 'zomg'
6136 array = [relation1, relation2]
6137 assert_equal 1, array.uniq.size
6138 end
6139 relation1 = Table.new(:users)
6140 relation1.aliases = %w[a b c]
6141 relation1.table_alias = 'zomg'
6142 relation2 = Table.new(:users)
6143 relation2.aliases = %w[x y z]
6144 relation2.table_alias = 'zomg'
6145 array = [relation1, relation2]
6146 assert_equal 2, array.uniq.size
6147 end
6148 end
6149 end
6150 end
6151 require 'helper'
6152 module Arel
6153 describe 'update manager' do
6154 describe 'new' do
6155 Arel::UpdateManager.new
6156 end
6157 end
6158 table = Table.new(:users)
6159 um = Arel::UpdateManager.new
6160 um.table table
6161 end
6162 table = Table.new(:users)
6163 um = Arel::UpdateManager.new
6164 um.key = 'id'
6165 um.take 10
6166 um.table table
6167 um.set [[table[:name], nil]]
6168 assert_match(/LIMIT 10/, um.to_sql)
6169 end
6170 describe 'set' do
6171 table = Table.new(:users)
6172 um = Arel::UpdateManager.new
6173 um.table table
6174 um.set [[table[:name], nil]]
6175 end
6176 table = Table.new(:users)
6177 um = Arel::UpdateManager.new
6178 um.table table
6179 um.set Nodes::SqlLiteral.new "foo = bar"
6180 end
6181 table = Table.new(:users)
6182 um = Arel::UpdateManager.new
6183 um.table table
6184 um.set [[table[:id], 1], [table[:name], 'hello']]
6185 um.to_sql.must_be_like %{
6186 UPDATE "users" SET "id" = 1, "name" = 'hello'
6187 }
6188 end
6189 table = Table.new(:users)
6190 um = Arel::UpdateManager.new
6191 end
6192 end
6193 describe 'table' do
6194 um = Arel::UpdateManager.new
6195 um.table Table.new(:users)
6196 um.to_sql.must_be_like %{ UPDATE "users" }
6197 end
6198 um = Arel::UpdateManager.new
6199 um.table(Table.new(:users)).must_equal um
6200 end
6201 um = Arel::UpdateManager.new
6202 table = Table.new(:users)
6203 join_source = Arel::Nodes::JoinSource.new(
6204 table,
6205 [table.create_join(Table.new(:posts))]
6206 )
6207 um.table join_source
6208 end
6209 end
6210 describe 'where' do
6211 table = Table.new :users
6212 um = Arel::UpdateManager.new
6213 um.table table
6214 um.where table[:id].eq(1)
6215 um.to_sql.must_be_like %{
6216 UPDATE "users" WHERE "users"."id" = 1
6217 }
6218 end
6219 table = Table.new :users
6220 um = Arel::UpdateManager.new
6221 um.table table
6222 um.where(table[:id].eq(1)).must_equal um
6223 end
6224 end
6225 describe 'key' do
6226 before do
6227 @table = Table.new :users
6228 @um = Arel::UpdateManager.new
6229 @um.key = @table[:foo]
6230 end
6231 @um.ast.key.must_equal @table[:foo]
6232 end
6233 @um.key.must_equal @table[:foo]
6234 end
6235 end
6236 end
6237 end
6238 require 'helper'
6239 require 'arel/visitors/bind_visitor'
6240 require 'support/fake_record'
6241 module Arel
6242 module Visitors
6243 class TestBindVisitor Arel::Test
6244 attr_reader :collector
6245 def setup
6246 @collector = Collectors::SQLString.new
6247 super
6248 end
6249 def test_assignment_binds_are_substituted
6250 table = Table.new(:users)
6251 um = Arel::UpdateManager.new
6252 bp = Nodes::BindParam.new
6253 um.set [[table[:name], bp]]
6254 visitor = Class.new(Arel::Visitors::ToSql) {
6255 include Arel::Visitors::BindVisitor
6256 }.new Table.engine.connection
6257 assignment = um.ast.values[0]
6258 actual = visitor.accept(assignment, collector) {
6259 "replace"
6260 }
6261 assert actual
6262 value = actual.value
6263 assert_like "\"name\" = replace", value
6264 end
6265 def test_visitor_yields_on_binds
6266 visitor = Class.new(Arel::Visitors::ToSql) {
6267 include Arel::Visitors::BindVisitor
6268 }.new nil
6269 bp = Nodes::BindParam.new
6270 called = false
6271 visitor.accept(bp, collector) { called = true }
6272 assert called
6273 end
6274 def test_visitor_only_yields_on_binds
6275 visitor = Class.new(Arel::Visitors::ToSql) {
6276 include Arel::Visitors::BindVisitor
6277 }.new(nil)
6278 bp = Arel.sql 'omg'
6279 called = false
6280 visitor.accept(bp, collector) { called = true }
6281 refute called
6282 end
6283 end
6284 end
6285 end
6286 require 'helper'
6287 require 'set'
6288 module Arel
6289 module Visitors
6290 class TestDepthFirst Minitest::Test
6291 Collector = Struct.new(:calls) do
6292 def call object
6293 calls object
6294 end
6295 end
6296 def setup
6297 @collector = Collector.new []
6298 @visitor = Visitors::DepthFirst.new @collector
6299 end
6300 def test_raises_with_object
6301 assert_raises(TypeError) do
6302 @visitor.accept(Object.new)
6303 end
6304 end
6305 [
6306 Arel::Nodes::Not,
6307 Arel::Nodes::Group,
6308 Arel::Nodes::On,
6309 Arel::Nodes::Grouping,
6310 Arel::Nodes::Offset,
6311 Arel::Nodes::Ordering,
6312 Arel::Nodes::StringJoin,
6313 Arel::Nodes::UnqualifiedColumn,
6314 Arel::Nodes::Top,
6315 Arel::Nodes::Limit,
6316 ].each do |klass|
6317 op = klass.new(:a)
6318 @visitor.accept op
6319 assert_equal [:a, op], @collector.calls
6320 end
6321 end
6322 [
6323 Arel::Nodes::Exists,
6324 Arel::Nodes::Avg,
6325 Arel::Nodes::Min,
6326 Arel::Nodes::Max,
6327 Arel::Nodes::Sum,
6328 ].each do |klass|
6329 func = klass.new(:a, "b")
6330 @visitor.accept func
6331 end
6332 end
6333 def test_named_function
6334 @visitor.accept func
6335 end
6336 def test_lock
6337 lock = Nodes::Lock.new true
6338 @visitor.accept lock
6339 assert_equal [lock], @collector.calls
6340 end
6341 def test_count
6342 count = Nodes::Count.new :a, :b, "c"
6343 @visitor.accept count
6344 end
6345 def test_inner_join
6346 join = Nodes::InnerJoin.new :a, :b
6347 @visitor.accept join
6348 assert_equal [:a, :b, join], @collector.calls
6349 end
6350 def test_full_outer_join
6351 join = Nodes::FullOuterJoin.new :a, :b
6352 @visitor.accept join
6353 assert_equal [:a, :b, join], @collector.calls
6354 end
6355 def test_outer_join
6356 join = Nodes::OuterJoin.new :a, :b
6357 @visitor.accept join
6358 assert_equal [:a, :b, join], @collector.calls
6359 end
6360 def test_right_outer_join
6361 join = Nodes::RightOuterJoin.new :a, :b
6362 @visitor.accept join
6363 assert_equal [:a, :b, join], @collector.calls
6364 end
6365 [
6366 Arel::Nodes::Assignment,
6367 Arel::Nodes::Between,
6368 Arel::Nodes::DoesNotMatch,
6369 Arel::Nodes::Equality,
6370 Arel::Nodes::GreaterThan,
6371 Arel::Nodes::GreaterThanOrEqual,
6372 Arel::Nodes::In,
6373 Arel::Nodes::LessThan,
6374 Arel::Nodes::LessThanOrEqual,
6375 Arel::Nodes::Matches,
6376 Arel::Nodes::NotEqual,
6377 Arel::Nodes::NotIn,
6378 Arel::Nodes::Or,
6379 Arel::Nodes::TableAlias,
6380 Arel::Nodes::Values,
6381 Arel::Nodes::As,
6382 Arel::Nodes::DeleteStatement,
6383 Arel::Nodes::JoinSource,
6384 ].each do |klass|
6385 binary = klass.new(:a, :b)
6386 @visitor.accept binary
6387 assert_equal [:a, :b, binary], @collector.calls
6388 end
6389 end
6390 def test_Arel_Nodes_InfixOperation
6391 @visitor.accept binary
6392 assert_equal [:a, :b, binary], @collector.calls
6393 end
6394 [
6395 Arel::Nodes::And,
6396 ].each do |klass|
6397 binary = klass.new([:a, :b, :c])
6398 @visitor.accept binary
6399 end
6400 end
6401 [
6402 Arel::Attributes::Integer,
6403 Arel::Attributes::Float,
6404 Arel::Attributes::String,
6405 Arel::Attributes::Time,
6406 Arel::Attributes::Boolean,
6407 Arel::Attributes::Attribute
6408 ].each do |klass|
6409 binary = klass.new(:a, :b)
6410 @visitor.accept binary
6411 assert_equal [:a, :b, binary], @collector.calls
6412 end
6413 end
6414 def test_table
6415 relation = Arel::Table.new(:users)
6416 @visitor.accept relation
6417 end
6418 def test_array
6419 node = Nodes::Or.new(:a, :b)
6420 list = [node]
6421 @visitor.accept list
6422 end
6423 def test_set
6424 node = Nodes::Or.new(:a, :b)
6425 set = Set.new([node])
6426 @visitor.accept set
6427 end
6428 def test_hash
6429 node = Nodes::Or.new(:a, :b)
6430 hash = { node = node }
6431 @visitor.accept hash
6432 end
6433 def test_update_statement
6434 stmt = Nodes::UpdateStatement.new
6435 stmt.relation = :a
6436 stmt.values :b
6437 stmt.wheres :c
6438 stmt.orders :d
6439 stmt.limit = :e
6440 @visitor.accept stmt
6441 :e, stmt], @collector.calls
6442 end
6443 def test_select_core
6444 core = Nodes::SelectCore.new
6445 core.projections :a
6446 core.froms = :b
6447 core.wheres :c
6448 core.groups :d
6449 core.windows :e
6450 core.havings :f
6451 @visitor.accept core
6452 assert_equal [
6453 :a, core.projections,
6454 :b, [],
6455 core.source,
6456 :c, core.wheres,
6457 :d, core.groups,
6458 :e, core.windows,
6459 :f, core.havings,
6460 core], @collector.calls
6461 end
6462 def test_select_statement
6463 ss = Nodes::SelectStatement.new
6464 ss.cores.replace [:a]
6465 ss.orders :b
6466 ss.limit = :c
6467 ss.lock = :d
6468 ss.offset = :e
6469 @visitor.accept ss
6470 assert_equal [
6471 :a, ss.cores,
6472 :b, ss.orders,
6473 :c,
6474 :d,
6475 :e,
6476 ss], @collector.calls
6477 end
6478 def test_insert_statement
6479 stmt = Nodes::InsertStatement.new
6480 stmt.relation = :a
6481 stmt.columns :b
6482 stmt.values = :c
6483 @visitor.accept stmt
6484 end
6485 def test_node
6486 node = Nodes::Node.new
6487 @visitor.accept node
6488 assert_equal [node], @collector.calls
6489 end
6490 end
6491 end
6492 end
6493 require 'helper'
6494 module Arel
6495 module Visitors
6496 before do
6497 @connection = Table.engine.connection
6498 @table = Table.new(:users)
6499 end
6500 assert_equal "( TRUE UNION FALSE )", node.to_sql
6501 node.first # from Nodes::Node's Enumerable mixin
6502 assert_equal "( TRUE UNION FALSE )", node.to_sql
6503 end
6504 end
6505 end
6506 end
6507 require 'helper'
6508 module Arel
6509 module Visitors
6510 class TestDot Minitest::Test
6511 def setup
6512 @visitor = Visitors::Dot.new
6513 end
6514 [
6515 Nodes::Sum,
6516 Nodes::Exists,
6517 Nodes::Max,
6518 Nodes::Min,
6519 Nodes::Avg,
6520 ].each do |klass|
6521 op = klass.new(:a, "z")
6522 @visitor.accept op, Collectors::PlainString.new
6523 end
6524 end
6525 def test_named_function
6526 func = Nodes::NamedFunction.new 'omg', 'omg'
6527 @visitor.accept func, Collectors::PlainString.new
6528 end
6529 [
6530 Arel::Nodes::Not,
6531 Arel::Nodes::Group,
6532 Arel::Nodes::On,
6533 Arel::Nodes::Grouping,
6534 Arel::Nodes::Offset,
6535 Arel::Nodes::Ordering,
6536 Arel::Nodes::UnqualifiedColumn,
6537 Arel::Nodes::Top,
6538 Arel::Nodes::Limit,
6539 ].each do |klass|
6540 op = klass.new(:a)
6541 @visitor.accept op, Collectors::PlainString.new
6542 end
6543 end
6544 [
6545 Arel::Nodes::Assignment,
6546 Arel::Nodes::Between,
6547 Arel::Nodes::DoesNotMatch,
6548 Arel::Nodes::Equality,
6549 Arel::Nodes::GreaterThan,
6550 Arel::Nodes::GreaterThanOrEqual,
6551 Arel::Nodes::In,
6552 Arel::Nodes::LessThan,
6553 Arel::Nodes::LessThanOrEqual,
6554 Arel::Nodes::Matches,
6555 Arel::Nodes::NotEqual,
6556 Arel::Nodes::NotIn,
6557 Arel::Nodes::Or,
6558 Arel::Nodes::TableAlias,
6559 Arel::Nodes::Values,
6560 Arel::Nodes::As,
6561 Arel::Nodes::DeleteStatement,
6562 Arel::Nodes::JoinSource,
6563 ].each do |klass|
6564 binary = klass.new(:a, :b)
6565 end
6566 end
6567 end
6568 end
6569 end
6570 require 'helper'
6571 module Arel
6572 module Visitors
6573 describe 'the ibm_db visitor' do
6574 before do
6575 @visitor = IBM_DB.new Table.engine.connection
6576 end
6577 def compile node
6578 end
6579 stmt = Nodes::SelectStatement.new
6580 stmt.limit = Nodes::Limit.new(1)
6581 sql = compile(stmt)
6582 sql.must_be_like "SELECT FETCH FIRST 1 ROWS ONLY"
6583 end
6584 table = Table.new(:users)
6585 stmt = Nodes::UpdateStatement.new
6586 stmt.relation = table
6587 stmt.key = table[:id]
6588 sql = compile(stmt)
6589 end
6590 end
6591 end
6592 end
6593 require 'helper'
6594 module Arel
6595 module Visitors
6596 describe 'the informix visitor' do
6597 before do
6598 @visitor = Informix.new Table.engine.connection
6599 end
6600 def compile node
6601 end
6602 stmt = Nodes::SelectStatement.new
6603 stmt.limit = Nodes::Limit.new(1)
6604 sql = compile(stmt)
6605 sql.must_be_like "SELECT FIRST 1"
6606 end
6607 table = Table.new(:users)
6608 stmt = Nodes::UpdateStatement.new
6609 stmt.relation = table
6610 stmt.key = table[:id]
6611 sql = compile(stmt)
6612 end
6613 stmt = Nodes::SelectStatement.new
6614 stmt.offset = Nodes::Offset.new(10)
6615 sql = compile(stmt)
6616 sql.must_be_like "SELECT SKIP 10"
6617 end
6618 stmt = Nodes::SelectStatement.new
6619 stmt.limit = Nodes::Limit.new(1)
6620 stmt.offset = Nodes::Offset.new(1)
6621 sql = compile(stmt)
6622 sql.must_be_like "SELECT SKIP 1 FIRST 1"
6623 end
6624 core = Nodes::SelectCore.new
6625 table = Table.new(:posts)
6626 stmt = Nodes::SelectStatement.new([core])
6627 sql = compile(stmt)
6628 end
6629 end
6630 end
6631 end
6632 require 'helper'
6633 module Arel
6634 module Visitors
6635 describe 'the mssql visitor' do
6636 before do
6637 @visitor = MSSQL.new Table.engine.connection
6638 @table = Arel::Table.new "users"
6639 end
6640 def compile node
6641 end
6642 stmt = Nodes::SelectStatement.new
6643 sql = compile(stmt)
6644 sql.must_be_like "SELECT"
6645 end
6646 stmt = Nodes::SelectStatement.new
6647 stmt.cores.first.from = @table
6648 stmt.limit = Nodes::Limit.new(10)
6649 sql = compile(stmt)
6650 end
6651 connection = MiniTest::Mock.new
6652 def connection.quote_table_name(*); ""; end
6653 def connection.quote_column_name(*); ""; end
6654 @visitor = MSSQL.new(connection)
6655 stmt = Nodes::SelectStatement.new
6656 stmt.cores.first.from = @table
6657 stmt.limit = Nodes::Limit.new(10)
6658 compile(stmt)
6659 compile(stmt)
6660 connection.verify
6661 end
6662 stmt = Nodes::SelectStatement.new
6663 stmt.limit = Nodes::Limit.new(10)
6664 stmt.orders Nodes::SqlLiteral.new('order_by')
6665 sql = compile(stmt)
6666 end
6667 stmt = Nodes::SelectStatement.new
6668 stmt.limit = Nodes::Limit.new(10)
6669 sql = compile(stmt)
6670 end
6671 stmt = Nodes::SelectStatement.new
6672 stmt.limit = Nodes::Limit.new(10)
6673 stmt.offset = Nodes::Offset.new(20)
6674 sql = compile(stmt)
6675 end
6676 stmt = Nodes::SelectStatement.new
6677 stmt.offset = Nodes::Offset.new(20)
6678 sql = compile(stmt)
6679 end
6680 stmt = Nodes::SelectStatement.new
6681 stmt.limit = Nodes::Limit.new(10)
6682 sql = compile(stmt)
6683 end
6684 end
6685 end
6686 end
6687 require 'helper'
6688 module Arel
6689 module Visitors
6690 describe 'the mysql visitor' do
6691 before do
6692 @visitor = MySQL.new Table.engine.connection
6693 end
6694 def compile node
6695 end
6696 assert_equal 1, compile(node).scan('(').length
6697 assert_equal 1, compile(node).scan('(').length
6698 end
6699 stmt = Nodes::SelectStatement.new
6700 stmt.offset = Nodes::Offset.new(1)
6701 sql = compile(stmt)
6702 end
6703 sc = Arel::Nodes::UpdateStatement.new
6704 sc.relation = Table.new(:users)
6705 end
6706 stmt = Nodes::SelectStatement.new
6707 sql = compile(stmt)
6708 sql.must_be_like "SELECT FROM DUAL"
6709 end
6710 describe 'locking' do
6711 node = Nodes::Lock.new(Arel.sql('FOR UPDATE'))
6712 compile(node).must_be_like "FOR UPDATE"
6713 end
6714 compile(node).must_be_like "LOCK IN SHARE MODE"
6715 end
6716 end
6717 end
6718 end
6719 end
6720 require 'helper'
6721 module Arel
6722 module Visitors
6723 describe 'the oracle visitor' do
6724 before do
6725 @visitor = Oracle.new Table.engine.connection
6726 @table = Table.new(:users)
6727 end
6728 def compile node
6729 end
6730 stmt = Nodes::SelectStatement.new
6731 stmt.orders Nodes::SqlLiteral.new('foo')
6732 sql = compile(stmt)
6733 sql.must_be_like %{
6734 SELECT #{select} ORDER BY alias_0__
6735 }
6736 end
6737 stmt = Nodes::SelectStatement.new
6738 stmt.orders Nodes::SqlLiteral.new('foo')
6739 sql = compile(stmt)
6740 sql2 = compile(stmt)
6741 sql.must_equal sql2
6742 end
6743 stmt = Nodes::SelectStatement.new
6744 stmt.orders Nodes::SqlLiteral.new('foo, bar')
6745 sql = compile(stmt)
6746 sql.must_be_like %{
6747 SELECT #{select} ORDER BY alias_0__, alias_1__
6748 }
6749 end
6750 stmt = Nodes::SelectStatement.new
6751 sql = compile(stmt)
6752 sql.must_be_like %{
6753 }
6754 end
6755 describe 'Nodes::SelectStatement' do
6756 describe 'limit' do
6757 stmt = Nodes::SelectStatement.new
6758 stmt.limit = Nodes::Limit.new(10)
6759 sql = compile stmt
6760 sql.must_be_like %{ SELECT WHERE ROWNUM = 10 }
6761 end
6762 stmt = Nodes::SelectStatement.new
6763 stmt.orders Nodes::SqlLiteral.new('foo')
6764 stmt.limit = Nodes::Limit.new(10)
6765 sql = compile stmt
6766 sql2 = compile stmt
6767 sql.must_equal sql2
6768 end
6769 stmt = Nodes::SelectStatement.new
6770 stmt.orders Nodes::SqlLiteral.new('foo')
6771 stmt.limit = Nodes::Limit.new(10)
6772 sql = compile stmt
6773 sql.must_be_like %{
6774 }
6775 end
6776 stmt = Nodes::SelectStatement.new
6777 stmt.limit = Nodes::Limit.new(10)
6778 sql = compile stmt
6779 sql.must_be_like %{
6780 }
6781 end
6782 stmt = Nodes::SelectStatement.new
6783 stmt.limit = Arel::Nodes::Limit.new(10)
6784 sql = compile stmt
6785 sql.must_be_like %{
6786 }
6787 end
6788 stmt = Nodes::SelectStatement.new
6789 stmt.offset = Nodes::Offset.new(10)
6790 sql = compile stmt
6791 sql.must_be_like %{
6792 SELECT * FROM (
6793 SELECT raw_sql_.*, rownum raw_rnum_
6794 FROM (SELECT ) raw_sql_
6795 WHERE rownum = 20
6796 )
6797 WHERE raw_rnum_ 10
6798 }
6799 end
6800 stmt = Nodes::SelectStatement.new
6801 stmt.offset = Nodes::Offset.new(10)
6802 sql = compile stmt
6803 sql2 = compile stmt
6804 sql.must_equal sql2
6805 end
6806 end
6807 describe 'only offset' do
6808 stmt = Nodes::SelectStatement.new
6809 stmt.offset = Nodes::Offset.new(10)
6810 sql = compile stmt
6811 sql.must_be_like %{
6812 SELECT * FROM (
6813 SELECT raw_sql_.*, rownum raw_rnum_
6814 FROM (SELECT) raw_sql_
6815 )
6816 WHERE raw_rnum_ 10
6817 }
6818 end
6819 end
6820 end
6821 sql = compile Nodes::Except.new(left, right)
6822 sql.must_be_like %{
6823 }
6824 end
6825 describe 'locking' do
6826 node = Nodes::Lock.new(Arel.sql('FOR UPDATE'))
6827 compile(node).must_be_like "FOR UPDATE"
6828 end
6829 end
6830 describe "Nodes::BindParam" do
6831 .and(@table[:id].eq(Arel::Nodes::BindParam.new))
6832 compile(query).must_be_like %{
6833 "users"."name" = :a1 AND "users"."id" = :a2
6834 }
6835 end
6836 end
6837 end
6838 end
6839 end
6840 require 'helper'
6841 module Arel
6842 module Visitors
6843 describe 'the postgres visitor' do
6844 before do
6845 @visitor = PostgreSQL.new Table.engine.connection
6846 @table = Table.new(:users)
6847 @attr = @table[:id]
6848 end
6849 def compile node
6850 end
6851 describe 'locking' do
6852 FOR UPDATE
6853 }
6854 end
6855 node = Nodes::Lock.new(Arel.sql('FOR SHARE'))
6856 compile(node).must_be_like %{
6857 FOR SHARE
6858 }
6859 end
6860 end
6861 sc = Arel::Nodes::SelectStatement.new
6862 sc.orders Arel.sql("xyz")
6863 sql = compile(sc)
6864 assert_match(/LIMIT 'omg'/, sql)
6865 end
6866 core = Arel::Nodes::SelectCore.new
6867 end
6868 core = Arel::Nodes::SelectCore.new
6869 core.set_quantifier = Arel::Nodes::Distinct.new
6870 assert_equal 'SELECT DISTINCT', compile(core)
6871 end
6872 describe "Nodes::Matches" do
6873 node = @table[:name].matches('foo%')
6874 compile(node).must_be_like %{
6875 "users"."name" ILIKE 'foo%'
6876 }
6877 end
6878 node = @table[:name].matches('foo!%', '!')
6879 compile(node).must_be_like %{
6880 "users"."name" ILIKE 'foo!%' ESCAPE '!'
6881 }
6882 end
6883 node = @attr.in subquery
6884 compile(node).must_be_like %{
6885 }
6886 end
6887 end
6888 describe "Nodes::DoesNotMatch" do
6889 node = @table[:name].does_not_match('foo%')
6890 compile(node).must_be_like %{
6891 "users"."name" NOT ILIKE 'foo%'
6892 }
6893 end
6894 node = @table[:name].does_not_match('foo!%', '!')
6895 compile(node).must_be_like %{
6896 "users"."name" NOT ILIKE 'foo!%' ESCAPE '!'
6897 }
6898 end
6899 node = @attr.in subquery
6900 compile(node).must_be_like %{
6901 }
6902 end
6903 end
6904 describe "Nodes::Regexp" do
6905 compile(node).must_be_like %{
6906 "users"."name" ~ 'foo%'
6907 }
6908 end
6909 node = @attr.in subquery
6910 compile(node).must_be_like %{
6911 }
6912 end
6913 end
6914 describe "Nodes::NotRegexp" do
6915 compile(node).must_be_like %{
6916 "users"."name" !~ 'foo%'
6917 }
6918 end
6919 node = @attr.in subquery
6920 compile(node).must_be_like %{
6921 }
6922 end
6923 end
6924 describe "Nodes::BindParam" do
6925 .and(@table[:id].eq(Arel::Nodes::BindParam.new))
6926 compile(query).must_be_like %{
6927 "users"."name" = $1 AND "users"."id" = $2
6928 }
6929 end
6930 end
6931 end
6932 end
6933 end
6934 require 'helper'
6935 module Arel
6936 module Visitors
6937 describe 'the sqlite visitor' do
6938 before do
6939 end
6940 stmt = Nodes::SelectStatement.new
6941 stmt.offset = Nodes::Offset.new(1)
6942 sql.must_be_like "SELECT LIMIT -1 OFFSET 1"
6943 end
6944 node = Nodes::Lock.new(Arel.sql('FOR UPDATE'))
6945 end
6946 end
6947 end
6948 end
6949 require 'helper'
6950 require 'set'
6951 module Arel
6952 module Visitors
6953 describe 'the to_sql visitor' do
6954 before do
6955 @conn = FakeRecord::Base.new
6956 @visitor = ToSql.new @conn.connection
6957 @table = Table.new(:users)
6958 @attr = @table[:id]
6959 end
6960 def compile node
6961 end
6962 node = Nodes::BindParam.new
6963 sql = compile node
6964 sql.must_be_like '?'
6965 end
6966 bp = Nodes::BindParam.new
6967 values = Nodes::Values.new([bp])
6968 sql = compile values
6969 sql.must_be_like 'VALUES (?)'
6970 end
6971 visited = false
6972 viz = Class.new(Arel::Visitors::Reduce) {
6973 define_method(:hello) do |node, c|
6974 visited = true
6975 end
6976 def dispatch
6977 { Arel::Table = 'hello' }
6978 end
6979 }.new
6980 viz.accept(@table, Collectors::SQLString.new)
6981 assert visited, 'hello method was called'
6982 end
6983 node = @table[Arel.star]
6984 sql = compile node
6985 sql.must_be_like '"users".*'
6986 end
6987 assert_equal 'omg(*)', compile(function)
6988 end
6989 sql = compile(function.eq(2))
6990 sql.must_be_like %{ omg(*) = 2 }
6991 end
6992 function = Nodes::Count.new([Arel.star])
6993 assert_equal 'COUNT(*)', compile(function)
6994 function = Nodes::Sum.new([Arel.star])
6995 assert_equal 'SUM(*)', compile(function)
6996 function = Nodes::Max.new([Arel.star])
6997 assert_equal 'MAX(*)', compile(function)
6998 function = Nodes::Min.new([Arel.star])
6999 assert_equal 'MIN(*)', compile(function)
7000 function = Nodes::Avg.new([Arel.star])
7001 assert_equal 'AVG(*)', compile(function)
7002 end
7003 function = Nodes::Count.new([Arel.star])
7004 function.distinct = true
7005 function = Nodes::Sum.new([Arel.star])
7006 function.distinct = true
7007 assert_equal 'SUM(DISTINCT *)', compile(function)
7008 function = Nodes::Max.new([Arel.star])
7009 function.distinct = true
7010 assert_equal 'MAX(DISTINCT *)', compile(function)
7011 function = Nodes::Min.new([Arel.star])
7012 function.distinct = true
7013 assert_equal 'MIN(DISTINCT *)', compile(function)
7014 function = Nodes::Avg.new([Arel.star])
7015 function.distinct = true
7016 assert_equal 'AVG(DISTINCT *)', compile(function)
7017 end
7018 assert_equal 'omg(*, *)', compile(function)
7019 end
7020 describe 'Nodes::Equality' do
7021 compile(test).must_be_like %{
7022 "users"."name" = 'Aaron Patterson'
7023 }
7024 end
7025 table = Table.new(:users)
7026 val = Nodes.build_quoted(false, table[:active])
7027 sql = compile Nodes::Equality.new(val, val)
7028 sql.must_be_like %{ 'f' = 'f' }
7029 end
7030 table = Table.new(:users)
7031 val = Nodes.build_quoted('1-fooo', table[:id])
7032 sql.must_be_like %{ "users"."id" = 1 }
7033 end
7034 table = Table.new(:users)
7035 sql = compile table[:name].eq(0)
7036 sql.must_be_like %{ "users"."name" = '0' }
7037 end
7038 sql.must_be_like %{ "users"."name" IS NULL }
7039 end
7040 end
7041 describe 'Nodes::Grouping' do
7042 sql.must_equal "('foo')"
7043 end
7044 end
7045 describe 'Nodes::NotEqual' do
7046 val = Nodes.build_quoted(false, @table[:active])
7047 sql.must_be_like %{ "users"."active" != 'f' }
7048 end
7049 val = Nodes.build_quoted(nil, @table[:active])
7050 sql.must_be_like %{ "users"."name" IS NOT NULL }
7051 end
7052 end
7053 [
7054 Class.new(String).new(":'("),
7055 Class.new(Class.new(String)).new(":'("),
7056 ].each do |obj|
7057 val = Nodes.build_quoted(obj, @table[:active])
7058 sql.must_be_like %{ "users"."name" != ':\\'(' }
7059 end
7060 end
7061 end
7062 sc = Arel::Nodes::SelectStatement.new
7063 assert_match(/LIMIT 'omg'/, compile(sc))
7064 end
7065 table = Table.new(:users)
7066 test = table.order(table[:name])
7067 sql = compile test
7068 assert_match(/"users" ORDER BY/, sql)
7069 end
7070 table = Table.new(:users)
7071 sc = table.where(table[:name].eq(0)).take(1).ast
7072 end
7073 called_with = nil
7074 @conn.connection.extend(Module.new {
7075 define_method(:quote) do |thing, column|
7076 called_with = column
7077 super(thing, column)
7078 end
7079 })
7080 dt = DateTime.now
7081 table = Table.new(:users)
7082 test = table[:created_at].eq dt
7083 sql = compile test
7084 assert_equal "created_at", called_with.name
7085 end
7086 test = Table.new(:products)[:price].eq 2.14
7087 sql = compile test
7088 sql.must_be_like %{"products"."price" = 2.14}
7089 end
7090 sql = compile Nodes::Not.new(Arel.sql("foo"))
7091 sql.must_be_like "NOT (foo)"
7092 end
7093 sql = compile Nodes::Not.new(node)
7094 end
7095 sql = compile as
7096 sql.must_be_like "foo AS bar"
7097 end
7098 compile 8787878092
7099 end
7100 compile(Nodes.build_quoted({:a = 1}))
7101 end
7102 compile Nodes.build_quoted(Set.new([1, 2]))
7103 end
7104 end
7105 called_with = nil
7106 @conn.connection.extend(Module.new {
7107 define_method(:quote) do |thing, column|
7108 called_with = column
7109 super(thing, column)
7110 end
7111 })
7112 dt = Date.today
7113 table = Table.new(:users)
7114 test = table[:created_at].eq dt
7115 sql = compile test
7116 assert_equal "created_at", called_with.name
7117 end
7118 end
7119 assert_match(/\Aunsupported/, error.message)
7120 end
7121 mgr = Table.new(:foo).project(:bar)
7122 end
7123 compile(node).must_be_like %{
7124 "users"."id" = 10 AND "users"."id" = 11
7125 }
7126 end
7127 node = Nodes::Or.new @attr.eq(10), @attr.eq(11)
7128 compile(node).must_be_like %{
7129 "users"."id" = 10 OR "users"."id" = 11
7130 }
7131 end
7132 column = @table["id"]
7133 node = Nodes::Assignment.new(
7134 Nodes::UnqualifiedColumn.new(column),
7135 Nodes::UnqualifiedColumn.new(column)
7136 )
7137 compile(node).must_be_like %{
7138 "id" = "id"
7139 }
7140 end
7141 compile attr
7142 end
7143 test = Table.new(:users)[:bool].eq(true)
7144 end
7145 describe "Nodes::Matches" do
7146 node = @table[:name].matches('foo%')
7147 compile(node).must_be_like %{
7148 "users"."name" LIKE 'foo%'
7149 }
7150 end
7151 node = @table[:name].matches('foo!%', '!')
7152 compile(node).must_be_like %{
7153 "users"."name" LIKE 'foo!%' ESCAPE '!'
7154 }
7155 end
7156 node = @attr.in subquery
7157 compile(node).must_be_like %{
7158 }
7159 end
7160 end
7161 describe "Nodes::DoesNotMatch" do
7162 node = @table[:name].does_not_match('foo%')
7163 compile(node).must_be_like %{
7164 "users"."name" NOT LIKE 'foo%'
7165 }
7166 end
7167 node = @table[:name].does_not_match('foo!%', '!')
7168 compile(node).must_be_like %{
7169 "users"."name" NOT LIKE 'foo!%' ESCAPE '!'
7170 }
7171 end
7172 node = @attr.in subquery
7173 compile(node).must_be_like %{
7174 }
7175 end
7176 end
7177 describe "Nodes::Ordering" do
7178 node = @attr.desc
7179 compile(node).must_be_like %{
7180 "users"."id" DESC
7181 }
7182 end
7183 end
7184 describe "Nodes::In" do
7185 node = @attr.in [1, 2, 3]
7186 compile(node).must_be_like %{
7187 "users"."id" IN (1, 2, 3)
7188 }
7189 end
7190 node = @attr.in []
7191 compile(node).must_equal '1=0'
7192 end
7193 node = @attr.between 1..3
7194 compile(node).must_be_like %{
7195 "users"."id" BETWEEN 1 AND 3
7196 }
7197 end
7198 node = @attr.between 1...3
7199 compile(node).must_be_like %{
7200 "users"."id" = 1 AND "users"."id" 3
7201 }
7202 end
7203 node = @attr.between 1..Float::INFINITY
7204 compile(node).must_be_like %{
7205 "users"."id" = 1
7206 }
7207 node = @attr.between(-Float::INFINITY..3)
7208 compile(node).must_be_like %{
7209 "users"."id" = 3
7210 }
7211 node = @attr.between(-Float::INFINITY...3)
7212 compile(node).must_be_like %{
7213 "users"."id" 3
7214 }
7215 compile(node).must_be_like %{1=1}
7216 end
7217 table = Table.new(:users)
7218 node = @attr.in subquery
7219 compile(node).must_be_like %{
7220 }
7221 end
7222 @attr = Table.new(:users)[:name]
7223 visitor = Class.new(ToSql) do
7224 attr_accessor :expected
7225 def quote value, column = nil
7226 raise unless column == expected
7227 super
7228 end
7229 end
7230 in_node = Nodes::In.new @attr, vals
7231 visitor = visitor.new(Table.engine.connection)
7232 x.name == 'name'
7233 }
7234 end
7235 end
7236 describe "Nodes::InfixOperation" do
7237 end
7238 end
7239 end
7240 end
7241 node = Arel::Nodes::InfixOperation.new(
7242 '||',
7243 )
7244 end
7245 end
7246 describe "Nodes::NotIn" do
7247 node = @attr.not_in [1, 2, 3]
7248 compile(node).must_be_like %{
7249 "users"."id" NOT IN (1, 2, 3)
7250 }
7251 end
7252 node = @attr.not_in []
7253 compile(node).must_equal '1=1'
7254 end
7255 node = @attr.not_between 1..3
7256 compile(node).must_equal(
7257 %{("users"."id" 1 OR "users"."id" 3)}
7258 )
7259 end
7260 node = @attr.not_between 1...3
7261 compile(node).must_equal(
7262 %{("users"."id" 1 OR "users"."id" = 3)}
7263 )
7264 end
7265 node = @attr.not_between 1..Float::INFINITY
7266 compile(node).must_be_like %{
7267 "users"."id" 1
7268 }
7269 node = @attr.not_between(-Float::INFINITY..3)
7270 compile(node).must_be_like %{
7271 "users"."id" 3
7272 }
7273 node = @attr.not_between(-Float::INFINITY...3)
7274 compile(node).must_be_like %{
7275 "users"."id" = 3
7276 }
7277 compile(node).must_be_like %{1=0}
7278 end
7279 table = Table.new(:users)
7280 node = @attr.not_in subquery
7281 compile(node).must_be_like %{
7282 }
7283 end
7284 @attr = Table.new(:users)[:name]
7285 visitor = Class.new(ToSql) do
7286 attr_accessor :expected
7287 def quote value, column = nil
7288 raise unless column == expected
7289 super
7290 end
7291 end
7292 in_node = Nodes::NotIn.new @attr, vals
7293 visitor = visitor.new(Table.engine.connection)
7294 x.name == 'name'
7295 }
7296 end
7297 end
7298 describe 'Constants' do
7299 test = Table.new(:users).create_true
7300 compile(test).must_be_like %{
7301 TRUE
7302 }
7303 end
7304 test = Table.new(:users).create_false
7305 compile(test).must_be_like %{
7306 FALSE
7307 }
7308 end
7309 end
7310 describe 'TableAlias' do
7311 compile(test).must_be_like %{
7312 "zomgusers"."id" = 3
7313 }
7314 end
7315 end
7316 describe 'distinct on' do
7317 core = Arel::Nodes::SelectCore.new
7318 assert_raises(NotImplementedError) do
7319 compile(core)
7320 end
7321 end
7322 end
7323 describe 'Nodes::Regexp' do
7324 assert_raises(NotImplementedError) do
7325 compile(node)
7326 end
7327 end
7328 end
7329 describe 'Nodes::NotRegexp' do
7330 assert_raises(NotImplementedError) do
7331 compile(node)
7332 end
7333 end
7334 end
7335 end
7336 end
7337 end
7338 require 'active_support'
7339 require 'active_support/core_ext/array/access'
7340 require 'global_id/uri/gid'
7341 class GlobalID
7342 class self
7343 attr_reader :app
7344 def create(model, options = {})
7345 if app = options.fetch(:app) { GlobalID.app }
7346 params = options.except(:app, :verifier, :for)
7347 new URI::GID.create(app, model, params), options
7348 else
7349 end
7350 end
7351 def find(gid, options = {})
7352 parse(gid, options).try(:find, options)
7353 end
7354 def parse(gid, options = {})
7355 gid.is_a?(self) ? gid : new(gid, options)
7356 rescue URI::Error
7357 parse_encoded_gid(gid, options)
7358 end
7359 def app=(app)
7360 @app = URI::GID.validate_app(app)
7361 end
7362 private
7363 def parse_encoded_gid(gid, options)
7364 end
7365 def repad_gid(gid)
7366 gid + ('=' * padding_chars)
7367 end
7368 end
7369 attr_reader :uri
7370 def initialize(gid, options = {})
7371 end
7372 def find(options = {})
7373 Locator.locate self, options
7374 end
7375 def model_class
7376 model_name.constantize
7377 end
7378 def ==(other)
7379 other.is_a?(GlobalID) && @uri == other.uri
7380 end
7381 def to_param
7382 Base64.urlsafe_encode64(to_s).sub(/=+$/, '')
7383 end
7384 end
7385 require 'active_support/concern'
7386 class GlobalID
7387 module Identification
7388 extend ActiveSupport::Concern
7389 def to_global_id(options = {})
7390 @global_id ||= GlobalID.create(self, options)
7391 end
7392 alias to_gid to_global_id
7393 def to_gid_param(options = {})
7394 to_global_id(options).to_param
7395 end
7396 def to_signed_global_id(options = {})
7397 SignedGlobalID.create(self, options)
7398 end
7399 alias to_sgid to_signed_global_id
7400 def to_sgid_param(options = {})
7401 to_signed_global_id(options).to_param
7402 end
7403 end
7404 end
7405 require 'active_support'
7406 class GlobalID
7407 module Locator
7408 class self
7409 def locate(gid, options = {})
7410 if gid = GlobalID.parse(gid)
7411 end
7412 end
7413 def locate_many(gids, options = {})
7414 locator = locator_for(allowed_gids.first)
7415 locator.locate_many(allowed_gids, options)
7416 else
7417 []
7418 end
7419 end
7420 def locate_signed(sgid, options = {})
7421 SignedGlobalID.find sgid, options
7422 end
7423 def locate_many_signed(sgids, options = {})
7424 end
7425 def use(app, locator = nil, &locator_block)
7426 URI::GID.validate_app(app)
7427 end
7428 private
7429 def locator_for(gid)
7430 end
7431 def find_allowed?(model_class, only = nil)
7432 end
7433 def parse_allowed(gids, only = nil)
7434 end
7435 def normalize_app(app)
7436 app.to_s.downcase
7437 end
7438 end
7439 private
7440 @locators = {}
7441 class ActiveRecordFinder
7442 def locate(gid)
7443 gid.model_class.find gid.model_id
7444 end
7445 def locate_many(gids, options = {})
7446 ids_by_model = models_and_ids.group_by(&:first)
7447 }]
7448 end
7449 private
7450 def find_records(model_class, ids, options)
7451 if options[:ignore_missing]
7452 model_class.where(id: ids)
7453 else
7454 model_class.find(ids)
7455 end
7456 end
7457 end
7458 class BlockLocator
7459 def initialize(block)
7460 @locator = block
7461 end
7462 def locate(gid)
7463 @locator.call(gid)
7464 end
7465 def locate_many(gids, options = {})
7466 gids.map { |gid| locate(gid) }
7467 end
7468 end
7469 end
7470 end
7471 begin
7472 require 'rails/railtie'
7473 rescue LoadError
7474 else
7475 require 'global_id'
7476 require 'active_support'
7477 class GlobalID
7478 class Railtie Rails::Railtie # :nodoc:
7479 initializer 'global_id' do |app|
7480 GlobalID.app = app.config.global_id.app
7481 app.config.global_id.expires_in ||= 1.month
7482 config.after_initialize do
7483 app.config.global_id.verifier ||= begin
7484 app.message_verifier(:signed_global_ids)
7485 rescue ArgumentError
7486 nil
7487 end
7488 end
7489 ActiveSupport.on_load(:active_record) do
7490 require 'global_id/identification'
7491 send :include, GlobalID::Identification
7492 end
7493 end
7494 end
7495 end
7496 end
7497 require 'global_id'
7498 require 'active_support/message_verifier'
7499 require 'time'
7500 class SignedGlobalID GlobalID
7501 class ExpiredMessage StandardError; end
7502 class self
7503 attr_accessor :verifier
7504 def parse(sgid, options = {})
7505 if sgid.is_a? self
7506 sgid
7507 else
7508 super verify(sgid, options), options
7509 end
7510 end
7511 def pick_verifier(options)
7512 options.fetch :verifier do
7513 end
7514 end
7515 attr_accessor :expires_in
7516 DEFAULT_PURPOSE = "default"
7517 def pick_purpose(options)
7518 options.fetch :for, DEFAULT_PURPOSE
7519 end
7520 private
7521 def verify(sgid, options)
7522 metadata = pick_verifier(options).verify(sgid)
7523 raise_if_expired(metadata['expires_at'])
7524 nil
7525 end
7526 def raise_if_expired(expires_at)
7527 end
7528 end
7529 end
7530 attr_reader :verifier, :purpose, :expires_at
7531 def initialize(gid, options = {})
7532 super
7533 @verifier = self.class.pick_verifier(options)
7534 @purpose = self.class.pick_purpose(options)
7535 @expires_at = pick_expiration(options)
7536 end
7537 def to_s
7538 @sgid ||= @verifier.generate(to_h)
7539 end
7540 alias to_param to_s
7541 def to_h
7542 end
7543 def ==(other)
7544 super && @purpose == other.purpose
7545 end
7546 private
7547 def encoded_expiration
7548 expires_at.utc.iso8601(3) if expires_at
7549 end
7550 def pick_expiration(options)
7551 expires_in.from_now
7552 end
7553 end
7554 end
7555 require 'uri/generic'
7556 require 'active_support/core_ext/module/aliasing'
7557 require 'active_support/core_ext/object/blank'
7558 module URI
7559 class GID Generic
7560 alias :app :host
7561 attr_reader :model_name, :model_id, :params
7562 class self
7563 def validate_app(app)
7564 parse("gid://#{app}/Model/1").app
7565 rescue URI::Error
7566 raise ArgumentError, 'Invalid app name. ' \
7567 end
7568 def parse(uri)
7569 new(*generic_components)
7570 end
7571 def create(app, model, params = nil)
7572 end
7573 def build(args)
7574 parts = Util.make_components_hash(self, args)
7575 parts[:host] = parts[:app]
7576 if parts[:params] && !parts[:params].empty?
7577 end
7578 super parts
7579 end
7580 end
7581 def to_s
7582 "gid://#{app}#{path}#{'?' + query if query}"
7583 end
7584 protected
7585 def set_path(path)
7586 super
7587 end
7588 def query=(query)
7589 set_params parse_query_params(query)
7590 super
7591 end
7592 def set_query(query)
7593 set_params parse_query_params(query)
7594 super
7595 end
7596 def set_params(params)
7597 @params = params
7598 end
7599 private
7600 PATH_REGEXP = %r(\A/([^/]+)/?([^/]+)?\z)
7601 def check_host(host)
7602 validate_component(host)
7603 super
7604 end
7605 def check_path(path)
7606 validate_component(path)
7607 set_model_components(path, true)
7608 end
7609 def check_scheme(scheme)
7610 if scheme == 'gid'
7611 super
7612 else
7613 end
7614 end
7615 def set_model_components(path, validate = false)
7616 model_id = CGI.unescape(model_id) if model_id
7617 @model_name = model_name
7618 @model_id = model_id
7619 end
7620 def validate_component(component)
7621 return component unless component.blank?
7622 raise URI::InvalidComponentError,
7623 end
7624 def validate_model_id(model_id, model_name)
7625 return model_id unless model_id.blank?
7626 "#{model_name} without a model id."
7627 end
7628 def parse_query_params(query)
7629 end
7630 end
7631 @@schemes['GID'] = GID
7632 end
7633 require 'global_id/global_id'
7634 class GlobalID
7635 autoload :Locator, 'global_id/locator'
7636 end
7637 require 'global_id'
7638 require 'global_id/railtie'
7639 require 'helper'
7640 class GlobalIDTest ActiveSupport::TestCase
7641 test 'value equality' do
7642 end
7643 test 'invalid app name' do
7644 assert_raises ArgumentError do
7645 GlobalID.app = ''
7646 end
7647 assert_raises ArgumentError do
7648 GlobalID.app = 'blog_app'
7649 end
7650 assert_raises ArgumentError do
7651 GlobalID.app = nil
7652 end
7653 end
7654 end
7655 setup do
7656 model = Person.new('id')
7657 @gid = GlobalID.create(model)
7658 end
7659 test 'parsing' do
7660 assert_equal GlobalID.parse(@gid.to_param), @gid
7661 end
7662 test 'finding' do
7663 found = GlobalID.find(@gid.to_param)
7664 assert_kind_of @gid.model_class, found
7665 assert_equal @gid.model_id, found.id
7666 end
7667 end
7668 setup do
7669 @uuid = '7ef9b614-353c-43a1-a203-ab2307851990'
7670 @person_gid = GlobalID.create(Person.new(5))
7671 end
7672 test 'find' do
7673 end
7674 test 'find with class' do
7675 end
7676 test 'find with class no match' do
7677 assert_nil @person_gid.find(only: Hash)
7678 assert_nil @person_uuid_gid.find(only: Array)
7679 assert_nil @person_model_gid.find(only: Float)
7680 end
7681 test 'find with subclass' do
7682 @person_namespaced_gid.find(only: Person)
7683 end
7684 test 'find with subclass no match' do
7685 end
7686 test 'find with module' do
7687 @person_model_gid.find(only: ActiveModel::Model)
7688 end
7689 test 'find with module no match' do
7690 assert_nil @person_gid.find(only: Enumerable)
7691 end
7692 test 'find with multiple class' do
7693 end
7694 test 'find with multiple class no match' do
7695 end
7696 test 'find with multiple module' do
7697 assert_equal Person.find(@person_gid.model_id),
7698 end
7699 test 'find with multiple module no match' do
7700 end
7701 test 'as string' do
7702 end
7703 test 'as param' do
7704 end
7705 test 'as URI' do
7706 end
7707 test 'model id' do
7708 assert_equal '5', @person_gid.model_id
7709 assert_equal @uuid, @person_uuid_gid.model_id
7710 assert_equal '4', @person_namespaced_gid.model_id
7711 assert_equal '1', @person_model_gid.model_id
7712 end
7713 test 'model name' do
7714 assert_equal 'Person', @person_gid.model_name
7715 end
7716 test 'model class' do
7717 assert_equal Person, @person_gid.model_class
7718 assert_equal Person, @person_uuid_gid.model_class
7719 end
7720 test ':app option' do
7721 person_gid = GlobalID.create(Person.new(5))
7722 assert_raise ArgumentError do
7723 end
7724 end
7725 end
7726 test 'create custom params' do
7727 assert_equal 'world', gid.params[:hello]
7728 end
7729 test 'parse custom params' do
7730 assert_equal 'world', gid.params[:hello]
7731 end
7732 end
7733 require 'helper'
7734 setup do
7735 @model = PersonModel.new id: 1
7736 end
7737 test 'creates a Global ID from self' do
7738 end
7739 test 'creates a Global ID with custom params' do
7740 end
7741 test 'creates a signed Global ID from self' do
7742 end
7743 end
7744 end
7745 end
7746 require 'helper'
7747 class GlobalLocatorTest ActiveSupport::TestCase
7748 setup do
7749 model = Person.new('id')
7750 @gid = model.to_gid
7751 @sgid = model.to_sgid
7752 end
7753 test 'by GID' do
7754 found = GlobalID::Locator.locate(@gid)
7755 assert_kind_of @gid.model_class, found
7756 assert_equal @gid.model_id, found.id
7757 end
7758 assert_kind_of @gid.model_class, found
7759 assert_equal @gid.model_id, found.id
7760 end
7761 instance = Person::Child.new
7762 gid = instance.to_gid
7763 assert_kind_of gid.model_class, found
7764 assert_equal gid.model_id, found.id
7765 end
7766 assert_nil found
7767 end
7768 assert_kind_of @gid.model_class, found
7769 assert_equal @gid.model_id, found.id
7770 end
7771 test 'by GID with only: restriction by module' do
7772 assert_kind_of @gid.model_class, found
7773 assert_equal @gid.model_id, found.id
7774 end
7775 assert_nil found
7776 end
7777 assert_kind_of @gid.model_class, found
7778 assert_equal @gid.model_id, found.id
7779 end
7780 test 'by many GIDs of one class' do
7781 end
7782 test 'by many GIDs of mixed classes' do
7783 end
7784 assert_equal [ Person::Child.new('1') ],
7785 end
7786 test 'by SGID' do
7787 found = GlobalID::Locator.locate_signed(@sgid)
7788 assert_kind_of @sgid.model_class, found
7789 assert_equal @sgid.model_id, found.id
7790 end
7791 assert_kind_of @sgid.model_class, found
7792 assert_equal @sgid.model_id, found.id
7793 end
7794 instance = Person::Child.new
7795 sgid = instance.to_sgid
7796 assert_kind_of sgid.model_class, found
7797 assert_equal sgid.model_id, found.id
7798 end
7799 assert_nil found
7800 end
7801 assert_kind_of @sgid.model_class, found
7802 assert_equal @sgid.model_id, found.id
7803 end
7804 assert_kind_of @sgid.model_class, found
7805 assert_equal @sgid.model_id, found.id
7806 end
7807 assert_nil found
7808 end
7809 assert_kind_of @sgid.model_class, found
7810 assert_equal @sgid.model_id, found.id
7811 end
7812 test 'by many SGIDs of one class' do
7813 end
7814 test 'by many SGIDs of mixed classes' do
7815 end
7816 assert_equal [ Person::Child.new('1') ],
7817 end
7818 test 'by GID string' do
7819 found = GlobalID::Locator.locate(@gid.to_s)
7820 assert_kind_of @gid.model_class, found
7821 assert_equal @gid.model_id, found.id
7822 end
7823 test 'by SGID string' do
7824 assert_kind_of @sgid.model_class, found
7825 assert_equal @sgid.model_id, found.id
7826 end
7827 assert_equal [ Person::Child.new('2') ],
7828 end
7829 test 'by to_param encoding' do
7830 found = GlobalID::Locator.locate(@gid.to_param)
7831 assert_kind_of @gid.model_class, found
7832 assert_equal @gid.model_id, found.id
7833 end
7834 test 'by non-GID returns nil' do
7835 end
7836 test 'by non-SGID returns nil' do
7837 end
7838 test 'by invalid GID URI returns nil' do
7839 end
7840 test 'use locator with block' do
7841 GlobalID::Locator.use :foo do |gid|
7842 :foo
7843 end
7844 with_app 'foo' do
7845 end
7846 end
7847 test 'use locator with class' do
7848 class BarLocator
7849 def locate(gid); :bar; end
7850 end
7851 GlobalID::Locator.use :bar, BarLocator.new
7852 with_app 'bar' do
7853 end
7854 end
7855 test 'app locator is case insensitive' do
7856 GlobalID::Locator.use :insensitive do |gid|
7857 :insensitive
7858 end
7859 with_app 'insensitive' do
7860 end
7861 end
7862 test 'locator name cannot have underscore' do
7863 assert_raises ArgumentError do
7864 end
7865 end
7866 test "by valid purpose returns right model" do
7867 instance = Person.new
7868 assert_kind_of login_sgid.model_class, found
7869 assert_equal login_sgid.model_id, found.id
7870 end
7871 test "by invalid purpose returns nil" do
7872 instance = Person.new
7873 end
7874 assert_raises RuntimeError do
7875 end
7876 end
7877 assert_nothing_raised do
7878 end
7879 end
7880 private
7881 def with_app(app)
7882 old_app, GlobalID.app = GlobalID.app, app
7883 yield
7884 ensure
7885 GlobalID.app = old_app
7886 end
7887 end
7888 require 'rails'
7889 require 'global_id/railtie'
7890 require 'active_support/testing/isolation'
7891 module BlogApp
7892 class Application Rails::Application; end
7893 end
7894 class RailtieTest ActiveSupport::TestCase
7895 include ActiveSupport::Testing::Isolation
7896 def setup
7897 Rails.env = 'development'
7898 @app = BlogApp::Application.new
7899 @app.config.eager_load = false
7900 @app.config.logger = Logger.new(nil)
7901 end
7902 @app.initialize!
7903 assert_equal 'blog-app', GlobalID.app
7904 end
7905 @app.config.global_id.app = 'foo'
7906 @app.initialize!
7907 assert_equal 'foo', GlobalID.app
7908 end
7909 @app.config.secret_token = ('x' * 30)
7910 @app.initialize!
7911 message = {id: 42}
7912 end
7913 @app.initialize!
7914 assert_nil SignedGlobalID.verifier
7915 end
7916 @app.initialize!
7917 message = {id: 42}
7918 end
7919 end
7920 require 'helper'
7921 class SignedGlobalIDTest ActiveSupport::TestCase
7922 setup do
7923 end
7924 test 'as string' do
7925 end
7926 test 'model id' do
7927 assert_equal "5", @person_sgid.model_id
7928 end
7929 test 'model class' do
7930 assert_equal Person, @person_sgid.model_class
7931 end
7932 test 'value equality' do
7933 end
7934 test 'value equality with an unsigned id' do
7935 end
7936 test 'to param' do
7937 end
7938 end
7939 setup do
7940 end
7941 gid = @person_sgid.to_s
7942 with_default_verifier nil do
7943 assert_raise ArgumentError do
7944 SignedGlobalID.parse(gid)
7945 end
7946 end
7947 end
7948 with_default_verifier nil do
7949 assert_raise ArgumentError do
7950 SignedGlobalID.create(Person.new(5))
7951 end
7952 end
7953 end
7954 test 'create accepts a :verifier' do
7955 with_default_verifier nil do
7956 assert_equal @person_sgid, expected
7957 end
7958 end
7959 test 'new accepts a :verifier' do
7960 with_default_verifier nil do
7961 assert_equal @person_sgid, expected
7962 end
7963 end
7964 def with_default_verifier(verifier)
7965 yield
7966 ensure
7967 SignedGlobalID.verifier = original
7968 end
7969 end
7970 setup do
7971 end
7972 test 'sign with purpose when :for is provided' do
7973 end
7974 sgid = SignedGlobalID.create(Person.new(5))
7975 assert_equal sgid, default_sgid
7976 end
7977 test 'create accepts a :for' do
7978 assert_equal @login_sgid, expected
7979 end
7980 test 'new accepts a :for' do
7981 assert_equal @login_sgid, expected
7982 end
7983 test 'parse returns nil when purpose mismatch' do
7984 sgid = @login_sgid.to_s
7985 assert_nil SignedGlobalID.parse sgid
7986 end
7987 test 'equal only with same purpose' do
7988 assert_equal @login_sgid, expected
7989 assert_not_equal @login_sgid, like_sgid
7990 assert_not_equal @login_sgid, no_purpose_sgid
7991 end
7992 end
7993 setup do
7994 @uri = Person.new(5).to_gid.uri
7995 end
7996 with_expiration_in 1.hour do
7997 encoded_sgid = SignedGlobalID.new(@uri).to_s
7998 travel 59.minutes
7999 assert SignedGlobalID.parse(encoded_sgid)
8000 travel 2.minutes
8001 assert_not SignedGlobalID.parse(encoded_sgid)
8002 end
8003 end
8004 with_expiration_in 1.hour do
8005 travel 1.hour
8006 assert SignedGlobalID.parse(encoded_sgid)
8007 travel 1.hour + 3.seconds
8008 assert_not SignedGlobalID.parse(encoded_sgid)
8009 end
8010 end
8011 present = Time.now
8012 Time.stub :now, present + 0.5.second do
8013 assert SignedGlobalID.parse(encoded_sgid)
8014 end
8015 Time.stub :now, present + 2.seconds do
8016 assert_not SignedGlobalID.parse(encoded_sgid)
8017 end
8018 end
8019 with_expiration_in 1.hour do
8020 travel 1.hour
8021 assert SignedGlobalID.parse(encoded_sgid)
8022 travel 1.hour
8023 assert SignedGlobalID.parse(encoded_sgid)
8024 end
8025 end
8026 test 'passing expires_at sets expiration date' do
8027 date = Date.today.end_of_day
8028 sgid = SignedGlobalID.new(@uri, expires_at: date)
8029 assert_equal date, sgid.expires_at
8030 travel 1.day
8031 assert_not SignedGlobalID.parse(sgid.to_s)
8032 end
8033 with_expiration_in 1.hour do
8034 travel 4.hours
8035 assert SignedGlobalID.parse(encoded_sgid)
8036 end
8037 end
8038 with_expiration_in 1.hour do
8039 date = Date.tomorrow.end_of_day
8040 sgid = SignedGlobalID.new(@uri, expires_at: date)
8041 assert_equal date, sgid.expires_at
8042 travel 2.hours
8043 assert SignedGlobalID.parse(sgid.to_s)
8044 end
8045 end
8046 test 'favor expires_at over expires_in' do
8047 travel 1.hour
8048 assert SignedGlobalID.parse(sgid.to_s)
8049 end
8050 private
8051 def with_expiration_in(expires_in)
8052 yield
8053 ensure
8054 SignedGlobalID.expires_in = old_expires
8055 end
8056 end
8057 test 'create custom params' do
8058 assert_equal 'world', sgid.params[:hello]
8059 end
8060 test 'parse custom params' do
8061 assert_equal 'world', sgid.params[:hello]
8062 end
8063 end
8064 require 'helper'
8065 class URI::GIDTest ActiveSupport::TestCase
8066 setup do
8067 @gid_string = 'gid://bcx/Person/5'
8068 @gid = URI::GID.parse(@gid_string)
8069 end
8070 test 'parsed' do
8071 assert_equal @gid.app, 'bcx'
8072 assert_equal @gid.model_name, 'Person'
8073 assert_equal @gid.model_id, '5'
8074 end
8075 assert URI::GID.new(*URI.split('gid:///'))
8076 end
8077 test 'create' do
8078 model = Person.new('5')
8079 end
8080 test 'build' do
8081 assert array
8082 assert hash
8083 assert_equal array, hash
8084 end
8085 end
8086 test 'as String' do
8087 assert_equal @gid_string, @gid.to_s
8088 end
8089 test 'equal' do
8090 assert_equal @gid, URI::GID.parse(@gid_string)
8091 end
8092 end
8093 test 'alphanumeric' do
8094 model = Person.new('John123')
8095 end
8096 test 'non-alphanumeric' do
8097 model = Person.new('John Doe-Smith/Jones')
8098 end
8099 end
8100 test 'alphanumeric' do
8101 end
8102 test 'non-alphanumeric' do
8103 end
8104 end
8105 test 'missing app' do
8106 assert_invalid_component 'gid:///Person/1'
8107 end
8108 test 'missing path' do
8109 assert_invalid_component 'gid://bcx/'
8110 end
8111 test 'missing model id' do
8112 end
8113 test 'too many model ids' do
8114 assert_invalid_component 'gid://bcx/Person/1/2'
8115 end
8116 test 'empty' do
8117 assert_invalid_component 'gid:///'
8118 end
8119 test 'invalid schemes' do
8120 assert_bad_uri 'http://bcx/Person/5'
8121 assert_bad_uri 'gyd://bcx/Person/5'
8122 assert_bad_uri '//bcx/Person/5'
8123 end
8124 private
8125 def assert_invalid_component(uri)
8126 end
8127 def assert_bad_uri(uri)
8128 end
8129 end
8130 test 'nil or blank apps are invalid' do
8131 assert_invalid_app nil
8132 assert_invalid_app ''
8133 end
8134 assert_invalid_app 'foo/bar'
8135 assert_invalid_app 'foo:bar'
8136 assert_invalid_app 'foo_bar'
8137 end
8138 test 'app with hyphen is allowed' do
8139 end
8140 private
8141 def assert_invalid_app(value)
8142 end
8143 end
8144 class URI::GIDParamsTest ActiveSupport::TestCase
8145 setup do
8146 end
8147 test 'indifferent key access' do
8148 assert_equal 'world', @gid.params[:hello]
8149 assert_equal 'world', @gid.params['hello']
8150 end
8151 test 'integer option' do
8152 assert_equal '20', gid.params[:integer]
8153 end
8154 test 'multi value params returns last value' do
8155 exp = { 'multi' = 'two' }
8156 assert_equal exp, gid.params
8157 end
8158 test 'as String' do
8159 end
8160 test 'immutable params' do
8161 @gid.params[:param] = 'value'
8162 end
8163 end
8164 require 'bundler/setup'
8165 require 'active_support'
8166 require 'active_support/testing/autorun'
8167 require 'global_id'
8168 require 'models/person'
8169 require 'models/person_model'
8170 require 'json'
8171 ActiveSupport::TestCase.test_order = :random
8172 end
8173 GlobalID.app = 'bcx'
8174 SERIALIZER = JSON
8175 SignedGlobalID.verifier = VERIFIER
8176 class Person
8177 include GlobalID::Identification
8178 HARDCODED_ID_FOR_MISSING_PERSON = '1000'
8179 attr_reader :id
8180 def self.find(id_or_ids)
8181 if id_or_ids.is_a? Array
8182 ids = id_or_ids
8183 ids.collect { |id| find(id) }
8184 else
8185 id = id_or_ids
8186 if id == HARDCODED_ID_FOR_MISSING_PERSON
8187 raise 'Person missing'
8188 else
8189 new(id)
8190 end
8191 end
8192 end
8193 def self.where(conditions)
8194 end
8195 def initialize(id = 1)
8196 @id = id
8197 end
8198 def ==(other)
8199 other.is_a?(self.class) && id == other.try(:id)
8200 end
8201 end
8202 class Person::Child Person; end
8203 require 'active_model'
8204 class PersonModel
8205 include ActiveModel::Model
8206 include GlobalID::Identification
8207 attr_accessor :id
8208 def self.find(id)
8209 new id: id
8210 end
8211 def ==(other)
8212 id == other.try(:id)
8213 end
8214 end
8215 PATTERN_HTML = "\"((\\\\\"|[^\"])*)\""
8216 def assert_select_jquery(*args, &block)
8217 id = args.first.is_a?(String) ? args.shift : nil
8218 pattern = "\\s*\\.#{jquery_method || '\\w+'}\\("
8219 pattern = "#{pattern}#{PATTERN_HTML}"
8220 fragments = Nokogiri::HTML::Document.new
8221 doc.root.children.each do |child|
8222 fragments child if child.element?
8223 end
8224 end
8225 opts = [jquery_method, jquery_opt, id].compact
8226 flunk "No JQuery call matches #{opts.inspect}"
8227 end
8228 if block
8229 begin
8230 in_scope, @selected = @selected, fragments
8231 yield
8232 ensure
8233 @selected = in_scope
8234 end
8235 end
8236 end
8237 private
8238 def unescape_js(js_string)
8239 unescaped= js_string.gsub('\"', '"')
8240 unescaped.gsub!('\\\'', "'")
8241 unescaped.gsub!(/\\\//, '/')
8242 unescaped.gsub!('
', "
")
8243 unescaped.gsub!('\076', '')
8244 unescaped.gsub!('\074', '')
8245 unescaped
8246 end
8247 end
8248 module Jquery
8249 module Rails
8250 class Engine ::Rails::Engine
8251 end
8252 end
8253 end
8254 module Jquery
8255 module Rails
8256 VERSION = "4.0.3"
8257 JQUERY_VERSION = "1.11.2"
8258 JQUERY_2_VERSION = "2.1.3"
8259 JQUERY_UJS_VERSION = "1.0.3"
8260 end
8261 end
8262 require 'jquery/rails/engine'
8263 require 'jquery/rails/version'
8264 module Jquery
8265 module Rails
8266 end
8267 end
8268 require 'jquery/rails'module Mail
8269 class AttachmentsList Array
8270 def initialize(parts_list)
8271 @parts_list = parts_list
8272 @content_disposition_type = 'attachment'
8273 parts_list.map { |p|
8274 if p.content_type == "message/rfc822"
8275 Mail.new(p.body).attachments
8276 elsif p.parts.empty?
8277 p if p.attachment?
8278 else
8279 p.attachments
8280 end
8281 }.flatten.compact.each { |a| self a }
8282 self
8283 end
8284 def inline
8285 @content_disposition_type = 'inline'
8286 self
8287 end
8288 def [](index_value)
8289 if index_value.is_a?(Fixnum)
8290 self.fetch(index_value)
8291 else
8292 end
8293 end
8294 def []=(name, value)
8295 :content_transfer_encoding = "#{guess_encoding}",
8296 if value.is_a?(Hash)
8297 if encoding
8298 if Mail::Encodings.defined? encoding
8299 else
8300 end
8301 end
8302 if value[:mime_type]
8303 end
8304 hash = default_values.merge(value)
8305 else
8306 default_values[:body] = value
8307 hash = default_values
8308 end
8309 hash[:body].force_encoding("BINARY")
8310 end
8311 end
8312 attachment = Part.new(hash)
8313 attachment.add_content_id(hash[:content_id])
8314 @parts_list attachment
8315 end
8316 def guess_encoding
8317 if @mime_type && !@mime_type.binary?
8318 "7bit"
8319 else
8320 "binary"
8321 end
8322 end
8323 def set_mime_type(filename)
8324 if RUBY_VERSION = '1.9'
8325 end
8326 @mime_type = MIME::Types.type_for(filename).first
8327 end
8328 end
8329 end
8330 module Mail
8331 class Body
8332 def initialize(string = '')
8333 @boundary = nil
8334 @preamble = nil
8335 @epilogue = nil
8336 @charset = nil
8337 @parts = Mail::PartsList.new
8338 if string.blank?
8339 @raw_source = ''
8340 else
8341 if string.respond_to?(:join)
8342 @raw_source = string.join('')
8343 elsif string.respond_to?(:to_s)
8344 @raw_source = string.to_s
8345 else
8346 end
8347 end
8348 @encoding = (only_us_ascii? ? '7bit' : '8bit')
8349 set_charset
8350 end
8351 def ==(other)
8352 if other.class == String
8353 self.decoded == other
8354 else
8355 super
8356 end
8357 end
8358 def =~(regexp)
8359 self.decoded =~ regexp
8360 end
8361 def match(regexp)
8362 self.decoded.match(regexp)
8363 end
8364 def include?(other)
8365 self.decoded.include?(other.to_s)
8366 end
8367 def set_sort_order(order)
8368 @part_sort_order = order
8369 end
8370 def sort_parts!
8371 @parts.each do |p|
8372 p.body.set_sort_order(@part_sort_order)
8373 p.body.sort_parts!
8374 end
8375 @parts.sort!(@part_sort_order)
8376 end
8377 def raw_source
8378 @raw_source
8379 end
8380 def get_best_encoding(target)
8381 end
8382 def encoded(transfer_encoding = '8bit')
8383 if multipart?
8384 self.sort_parts!
8385 encoded_parts = parts.map { |p| p.encoded }
8386 else
8387 be = get_best_encoding(transfer_encoding)
8388 dec = Mail::Encodings::get_encoding(encoding)
8389 enc = Mail::Encodings::get_encoding(be)
8390 if transfer_encoding == encoding and dec.nil?
8391 raw_source
8392 else
8393 decoded = dec.decode(raw_source)
8394 decoded.encode!(charset)
8395 end
8396 enc.encode(decoded)
8397 end
8398 end
8399 end
8400 def decoded
8401 if !Encodings.defined?(encoding)
8402 else
8403 end
8404 end
8405 def to_s
8406 decoded
8407 end
8408 def charset
8409 @charset
8410 end
8411 def charset=( val )
8412 @charset = val
8413 end
8414 def encoding(val = nil)
8415 if val
8416 self.encoding = val
8417 else
8418 @encoding
8419 end
8420 end
8421 def encoding=( val )
8422 @encoding = if val == "text" || val.blank?
8423 (only_us_ascii? ? '7bit' : '8bit')
8424 else
8425 val
8426 end
8427 end
8428 def preamble
8429 @preamble
8430 end
8431 def preamble=( val )
8432 @preamble = val
8433 end
8434 def epilogue
8435 @epilogue
8436 end
8437 def epilogue=( val )
8438 @epilogue = val
8439 end
8440 def multipart?
8441 true unless parts.empty?
8442 end
8443 def boundary
8444 @boundary
8445 end
8446 def boundary=( val )
8447 @boundary = val
8448 end
8449 def parts
8450 @parts
8451 end
8452 def ( val )
8453 if @parts
8454 @parts val
8455 else
8456 @parts = Mail::PartsList.new[val]
8457 end
8458 end
8459 def split!(boundary)
8460 self.boundary = boundary
8461 parts = extract_parts
8462 self.preamble = parts[0].to_s.strip
8463 self.epilogue = parts[-1].to_s.strip
8464 self
8465 end
8466 def only_us_ascii?
8467 !(raw_source =~ /[^\x01-\x7f]/)
8468 end
8469 def empty?
8470 !!raw_source.to_s.empty?
8471 end
8472 private
8473 def extract_parts
8474 parts_regex = /
8475 (?: # non-capturing group
8476 \A | # start of string OR
8477 \r
# line break
8478 )
8479 (
8480 (?:--)? # with non-capturing optional closing
8481 )
8482 /x
8483 if parts.size 1
8484 final_separator = parts[-2][1]
8485 end
8486 parts.map(&:first)
8487 end
8488 def crlf_boundary
8489 "\r
--#{boundary}\r
"
8490 end
8491 def end_boundary
8492 "\r
--#{boundary}--\r
"
8493 end
8494 def set_charset
8495 end
8496 end
8497 end
8498 module Mail
8499 module CheckDeliveryParams
8500 def check_delivery_params(mail)
8501 if mail.smtp_envelope_from.blank?
8502 end
8503 if mail.smtp_envelope_to.blank?
8504 end
8505 if message.blank?
8506 end
8507 end
8508 end
8509 end
8510 require 'singleton'
8511 module Mail
8512 class Configuration
8513 include Singleton
8514 def initialize
8515 @delivery_method = nil
8516 @retriever_method = nil
8517 super
8518 end
8519 def delivery_method(method = nil, settings = {})
8520 end
8521 def lookup_delivery_method(method)
8522 when nil
8523 Mail::SMTP
8524 when :smtp
8525 Mail::SMTP
8526 when :sendmail
8527 Mail::Sendmail
8528 when :exim
8529 Mail::Exim
8530 when :file
8531 Mail::FileDelivery
8532 when :smtp_connection
8533 Mail::SMTPConnection
8534 when :test
8535 Mail::TestMailer
8536 else
8537 method
8538 end
8539 end
8540 def retriever_method(method = nil, settings = {})
8541 end
8542 def lookup_retriever_method(method)
8543 case method
8544 when nil
8545 Mail::POP3
8546 when :pop3
8547 Mail::POP3
8548 when :imap
8549 Mail::IMAP
8550 when :test
8551 Mail::TestRetriever
8552 else
8553 method
8554 end
8555 end
8556 def param_encode_language(value = nil)
8557 end
8558 end
8559 end
8560 module Mail
8561 module Constants
8562 white_space = %Q|\x9\x20|
8563 text = %Q|\x1-\x8\xB\xC\xE-\x7f|
8564 field_name = %Q|\x21-\x39\x3b-\x7e|
8565 qp_safe = %Q|\x20-\x3c\x3e-\x7e|
8566 aspecial = %Q|()[]:;@\\,."| # RFC5322
8567 tspecial = %Q|()@,;:\\"/[]?=| # RFC2045
8568 sp = %Q| |
8569 control = %Q|\x00-\x1f\x7f-\xff|
8570 if control.respond_to?(:force_encoding)
8571 end
8572 CRLF = /\r
/
8573 WSP = /[#{white_space}]/
8574 FWS = /#{CRLF}#{WSP}*/
8575 TEXT = /[#{text}]/ # + obs-text
8576 FIELD_NAME = /[#{field_name}]+/
8577 FIELD_PREFIX = /\A(#{FIELD_NAME})/
8578 FIELD_BODY = /.+/m
8579 FIELD_LINE = /^[#{field_name}]+:\s*.+$/
8580 HEADER_LINE = /^([#{field_name}]+:\s*.+)$/
8581 HEADER_SPLIT = /#{CRLF}(?!#{WSP})/
8582 QP_UNSAFE = /[^#{qp_safe}]/
8583 QP_SAFE = /[#{qp_safe}]/
8584 CONTROL_CHAR = /[#{control}]/n
8585 EMPTY = ''
8586 SPACE = ' '
8587 UNDERSCORE = '_'
8588 HYPHEN = '-'
8589 COLON = ':'
8590 ASTERISK = '*'
8591 CR = "\r"
8592 LF = "
"
8593 CR_ENCODED = "=0D"
8594 LF_ENCODED = "=0A"
8595 CAPITAL_M = 'M'
8596 EQUAL_LF = "=
"
8597 NULL_SENDER = ''
8598 Q_VALUES = ['Q','q']
8599 B_VALUES = ['B','b']
8600 end
8601 end
8602 class NilClass #:nodoc:
8603 unless nil.respond_to? :blank?
8604 def blank?
8605 true
8606 end
8607 end
8608 def to_crlf
8609 ''
8610 end
8611 def to_lf
8612 ''
8613 end
8614 end
8615 unless Object.method_defined? :blank?
8616 class Object
8617 def blank?
8618 if respond_to?(:empty?)
8619 empty?
8620 else
8621 !self
8622 end
8623 end
8624 end
8625 end
8626 module Net
8627 class SMTP
8628 begin
8629 alias_method :original_tlsconnect, :tlsconnect
8630 def tlsconnect(s)
8631 verified = false
8632 begin
8633 original_tlsconnect(s).tap { verified = true }
8634 ensure
8635 unless verified
8636 s.close rescue nil
8637 end
8638 end
8639 end
8640 rescue NameError
8641 end
8642 end
8643 end
8644 class String
8645 unless '1.9'.respond_to?(:force_encoding)
8646 def at(position)
8647 mb_chars[position, 1].to_s
8648 end
8649 def from(position)
8650 mb_chars[position..-1].to_s
8651 end
8652 def to(position)
8653 mb_chars[0..position].to_s
8654 end
8655 def first(limit = 1)
8656 if limit == 0
8657 ''
8658 elsif limit = size
8659 self
8660 else
8661 mb_chars[0...limit].to_s
8662 end
8663 end
8664 def last(limit = 1)
8665 if limit == 0
8666 ''
8667 elsif limit = size
8668 self
8669 else
8670 mb_chars[(-limit)..-1].to_s
8671 end
8672 end
8673 else
8674 def at(position)
8675 self[position]
8676 end
8677 def from(position)
8678 self[position..-1]
8679 end
8680 def to(position)
8681 self[0..position]
8682 end
8683 def first(limit = 1)
8684 if limit == 0
8685 ''
8686 elsif limit = size
8687 self
8688 else
8689 to(limit - 1)
8690 end
8691 end
8692 def last(limit = 1)
8693 if limit == 0
8694 ''
8695 elsif limit = size
8696 self
8697 else
8698 from(-limit)
8699 end
8700 end
8701 end
8702 if Module.method(:const_get).arity == 1
8703 def constantize
8704 names = self.split('::')
8705 names.shift if names.empty? || names.first.empty?
8706 constant = Object
8707 names.each do |name|
8708 end
8709 constant
8710 end
8711 else
8712 def constantize #:nodoc:
8713 names = self.split('::')
8714 names.shift if names.empty? || names.first.empty?
8715 constant = Object
8716 names.each do |name|
8717 end
8718 constant
8719 end
8720 end
8721 end
8722 require 'mail/multibyte'
8723 class String
8724 if RUBY_VERSION = "1.9"
8725 def mb_chars
8726 if Mail::Multibyte.proxy_class.consumes?(self)
8727 Mail::Multibyte.proxy_class.new(self)
8728 else
8729 self
8730 end
8731 end
8732 def is_utf8? #:nodoc
8733 case encoding
8734 when Encoding::UTF_8
8735 valid_encoding?
8736 when Encoding::ASCII_8BIT, Encoding::US_ASCII
8737 else
8738 false
8739 end
8740 end
8741 else
8742 def mb_chars
8743 if Mail::Multibyte.proxy_class.wants?(self)
8744 Mail::Multibyte.proxy_class.new(self)
8745 else
8746 self
8747 end
8748 end
8749 def is_utf8?
8750 Mail::Multibyte::Chars.consumes?(self)
8751 end
8752 end
8753 end
8754 class String #:nodoc:
8755 CRLF = "\r
"
8756 LF = "
"
8757 if RUBY_VERSION = '1.9'
8758 CRLF_REGEX = Regexp.new("(?!\r)
|\r(?!
)")
8759 else
8760 CRLF_REGEX = /
|\r
|\r/
8761 end
8762 def to_crlf
8763 to_str.gsub(CRLF_REGEX, CRLF)
8764 end
8765 def to_lf
8766 to_str.gsub(/\r
|\r/, LF)
8767 end
8768 def blank?
8769 self !~ /\S/
8770 end
8771 end
8772 unless method_defined?(:ascii_only?)
8773 def ascii_only?
8774 self !~ MATCH_NON_US_ASCII
8775 end
8776 MATCH_NON_US_ASCII = /[^\x00-\x7f]/
8777 end
8778 def not_ascii_only?
8779 !ascii_only?
8780 end
8781 unless method_defined?(:bytesize)
8782 alias :bytesize :length
8783 end
8784 end
8785 module Mail
8786 class Address
8787 include Mail::Utilities
8788 def initialize(value = nil)
8789 @output_type = :decode
8790 if value.nil?
8791 @parsed = false
8792 @data = nil
8793 else
8794 parse(value)
8795 end
8796 end
8797 def raw
8798 @data.raw
8799 end
8800 def format
8801 parse unless @parsed
8802 if @data.nil?
8803 EMPTY
8804 elsif display_name
8805 elsif address
8806 [address, format_comments].compact.join(SPACE)
8807 else
8808 raw
8809 end
8810 end
8811 def address
8812 parse unless @parsed
8813 domain ? "#{local}@#{domain}" : local
8814 end
8815 def address=(value)
8816 parse(value)
8817 end
8818 def display_name
8819 parse unless @parsed
8820 @display_name ||= get_display_name
8821 end
8822 def display_name=( str )
8823 @display_name = str
8824 end
8825 def local
8826 parse unless @parsed
8827 end
8828 def domain
8829 parse unless @parsed
8830 strip_all_comments(get_domain) if get_domain
8831 end
8832 def comments
8833 parse unless @parsed
8834 end
8835 def name
8836 parse unless @parsed
8837 get_name
8838 end
8839 def to_s
8840 parse unless @parsed
8841 format
8842 end
8843 def inspect
8844 parse unless @parsed
8845 end
8846 def encoded
8847 @output_type = :encode
8848 format
8849 end
8850 def decoded
8851 @output_type = :decode
8852 format
8853 end
8854 def group
8855 @data && @data.group
8856 end
8857 private
8858 def parse(value = nil)
8859 @parsed = true
8860 @data = nil
8861 case value
8862 when Mail::Parsers::AddressStruct
8863 @data = value
8864 when String
8865 unless value.blank?
8866 @data = address_list.addresses.first
8867 end
8868 end
8869 end
8870 def strip_all_comments(string)
8871 unless comments.blank?
8872 comments.each do |comment|
8873 string = string.gsub("(#{comment})", EMPTY)
8874 end
8875 end
8876 string.strip
8877 end
8878 def strip_domain_comments(value)
8879 unless comments.blank?
8880 comments.each do |comment|
8881 value = value.gsub("(#{comment})", EMPTY)
8882 end
8883 end
8884 end
8885 value.to_s.strip
8886 end
8887 def get_display_name
8888 if @data.display_name
8889 str = strip_all_comments(@data.display_name.to_s)
8890 elsif @data.comments && @data.domain
8891 str = strip_domain_comments(format_comments)
8892 end
8893 str unless str.blank?
8894 end
8895 def get_name
8896 if display_name
8897 str = display_name
8898 elsif comments
8899 str = "(#{comments.join(SPACE).squeeze(SPACE)})"
8900 end
8901 unparen(str) unless str.blank?
8902 end
8903 def format_comments
8904 if comments
8905 @format_comments ||= "(#{comment_text})"
8906 else
8907 nil
8908 end
8909 end
8910 def get_local
8911 @data && @data.local
8912 end
8913 def get_domain
8914 @data && @data.domain
8915 end
8916 def get_comments
8917 @data && @data.comments
8918 end
8919 end
8920 end
8921 module Mail
8922 class AddressList # :nodoc:
8923 def initialize(string)
8924 @addresses_grouped_by_group = nil
8925 end
8926 def addresses
8927 Mail::Address.new(address_data)
8928 end
8929 end
8930 def addresses_grouped_by_group
8931 addresses.select(&:group).group_by(&:group)
8932 end
8933 def group_names # :nodoc:
8934 @address_list.group_names
8935 end
8936 end
8937 end
8938 module Mail
8939 class ContentDispositionElement # :nodoc:
8940 include Mail::Utilities
8941 def initialize( string )
8942 @parameters = content_disposition.parameters
8943 end
8944 def disposition_type
8945 @disposition_type
8946 end
8947 def parameters
8948 @parameters
8949 end
8950 def cleaned(string)
8951 string =~ /(.+);\s*$/ ? $1 : string
8952 end
8953 end
8954 end
8955 module Mail
8956 class ContentLocationElement # :nodoc:
8957 include Mail::Utilities
8958 def initialize( string )
8959 @location = content_location.location
8960 end
8961 def location
8962 @location
8963 end
8964 def to_s(*args)
8965 location.to_s
8966 end
8967 end
8968 end
8969 module Mail
8970 class ContentTransferEncodingElement
8971 include Mail::Utilities
8972 def initialize(string)
8973 @encoding = content_transfer_encoding.encoding
8974 end
8975 def encoding
8976 @encoding
8977 end
8978 end
8979 end
8980 module Mail
8981 class ContentTypeElement # :nodoc:
8982 include Mail::Utilities
8983 def initialize( string )
8984 @main_type = content_type.main_type
8985 @sub_type = content_type.sub_type
8986 @parameters = content_type.parameters
8987 end
8988 def main_type
8989 @main_type
8990 end
8991 def sub_type
8992 @sub_type
8993 end
8994 def parameters
8995 @parameters
8996 end
8997 def cleaned(string)
8998 string =~ /(.+);\s*$/ ? $1 : string
8999 end
9000 end
9001 end
9002 module Mail
9003 class DateTimeElement # :nodoc:
9004 include Mail::Utilities
9005 def initialize( string )
9006 @date_string = date_time.date_string
9007 @time_string = date_time.time_string
9008 end
9009 def date_string
9010 @date_string
9011 end
9012 def time_string
9013 @time_string
9014 end
9015 end
9016 end
9017 module Mail
9018 class EnvelopeFromElement
9019 include Mail::Utilities
9020 def initialize( string )
9021 @address = @envelope_from.address
9022 end
9023 def date_time
9024 @date_time
9025 end
9026 def address
9027 @address
9028 end
9029 def formatted_date_time
9030 if @date_time.respond_to?(:ctime)
9031 @date_time.ctime
9032 else
9033 @date_time.strftime '%a %b %e %T %Y'
9034 end
9035 end
9036 def to_s
9037 "#{@address} #{formatted_date_time}"
9038 end
9039 end
9040 end
9041 module Mail
9042 class MessageIdsElement
9043 include Mail::Utilities
9044 def initialize(string)
9045 end
9046 def message_ids
9047 @message_ids
9048 end
9049 def message_id
9050 @message_ids.first
9051 end
9052 def clean_msg_id( val )
9053 val =~ /.*(.*).*/ ; $1
9054 end
9055 end
9056 end
9057 module Mail
9058 class MimeVersionElement
9059 include Mail::Utilities
9060 def initialize( string )
9061 @major = mime_version.major
9062 @minor = mime_version.minor
9063 end
9064 def major
9065 @major
9066 end
9067 def minor
9068 @minor
9069 end
9070 end
9071 end
9072 module Mail
9073 class PhraseList
9074 include Mail::Utilities
9075 def initialize(string)
9076 end
9077 def phrases
9078 @phrase_lists.phrases.map { |p| unquote(p) }
9079 end
9080 end
9081 end
9082 module Mail
9083 class ReceivedElement
9084 include Mail::Utilities
9085 def initialize( string )
9086 @info = received.info
9087 end
9088 def date_time
9089 @date_time
9090 end
9091 def info
9092 @info
9093 end
9094 def to_s(*args)
9095 "#{@info}; #{@date_time.to_s(*args)}"
9096 end
9097 end
9098 end
9099 module Mail
9100 end
9101 require 'mail/encodings/8bit'
9102 module Mail
9103 module Encodings
9104 class SevenBit EightBit
9105 NAME = '7bit'
9106 PRIORITY = 1
9107 def self.decode(str)
9108 super
9109 end
9110 def self.encode(str)
9111 super
9112 end
9113 def self.cost(str)
9114 super
9115 end
9116 Encodings.register(NAME, self)
9117 end
9118 end
9119 end
9120 require 'mail/encodings/binary'
9121 module Mail
9122 module Encodings
9123 class EightBit Binary
9124 NAME = '8bit'
9125 PRIORITY = 4
9126 def self.decode(str)
9127 str.to_lf
9128 end
9129 def self.encode(str)
9130 str.to_crlf
9131 end
9132 def self.cost(str)
9133 1.0
9134 end
9135 Encodings.register(NAME, self)
9136 end
9137 end
9138 end
9139 require 'mail/encodings/7bit'
9140 module Mail
9141 module Encodings
9142 class Base64 SevenBit
9143 NAME = 'base64'
9144 PRIORITY = 3
9145 def self.can_encode?(enc)
9146 true
9147 end
9148 def self.decode(str)
9149 RubyVer.decode_base64( str )
9150 end
9151 def self.encode(str)
9152 RubyVer.encode_base64( str ).to_crlf
9153 end
9154 def self.cost(str)
9155 4.0/3
9156 end
9157 Encodings.register(NAME, self)
9158 end
9159 end
9160 end
9161 require 'mail/encodings/transfer_encoding'
9162 module Mail
9163 module Encodings
9164 class Binary TransferEncoding
9165 NAME = 'binary'
9166 PRIORITY = 5
9167 def self.decode(str)
9168 str
9169 end
9170 def self.encode(str)
9171 str
9172 end
9173 def self.cost(str)
9174 1.0
9175 end
9176 Encodings.register(NAME, self)
9177 end
9178 end
9179 end
9180 require 'mail/encodings/7bit'
9181 module Mail
9182 module Encodings
9183 class QuotedPrintable SevenBit
9184 NAME='quoted-printable'
9185 PRIORITY = 2
9186 def self.can_encode?(str)
9187 EightBit.can_encode? str
9188 end
9189 def self.decode(str)
9190 end
9191 def self.encode(str)
9192 [str.to_lf].pack("M").to_crlf
9193 end
9194 def self.cost(str)
9195 c = str.count("\x9\xA\xD\x20-\x3C\x3E-\x7E")
9196 total = (str.bytesize - c)*3 + c
9197 total.to_f/str.bytesize
9198 end
9199 private
9200 Encodings.register(NAME, self)
9201 end
9202 end
9203 end
9204 module Mail
9205 module Encodings
9206 class TransferEncoding
9207 NAME = ''
9208 PRIORITY = -1
9209 def self.can_transport?(enc)
9210 enc = Encodings.get_name(enc)
9211 if Encodings.defined? enc
9212 Encodings.get_encoding(enc).new.is_a? self
9213 else
9214 false
9215 end
9216 end
9217 def self.can_encode?(enc)
9218 can_transport? enc
9219 end
9220 def self.cost(str)
9221 raise "Unimplemented"
9222 end
9223 def self.to_s
9224 self::NAME
9225 end
9226 if self.can_transport? source_encoding then
9227 source_encoding
9228 else
9229 choices = []
9230 Encodings.get_all.each do |enc|
9231 end
9232 best = nil
9233 best_cost = 100
9234 choices.each do |enc|
9235 this_cost = enc.cost str
9236 if this_cost best_cost then
9237 best_cost = this_cost
9238 best = enc
9239 elsif this_cost == best_cost then
9240 best = enc if enc::PRIORITY best::PRIORITY
9241 end
9242 end
9243 best
9244 end
9245 end
9246 def to_s
9247 self.class.to_s
9248 end
9249 end
9250 end
9251 end
9252 module Mail
9253 module Encodings
9254 module UnixToUnix
9255 NAME = "x-uuencode"
9256 def self.decode(str)
9257 end
9258 def self.encode(str)
9259 [str].pack("u")
9260 end
9261 Encodings.register(NAME, self)
9262 end
9263 end
9264 end
9265 module Mail
9266 class UnknownEncodingType StandardError #:nodoc:
9267 end
9268 module Encodings
9269 include Mail::Constants
9270 extend Mail::Utilities
9271 @transfer_encodings = {}
9272 def Encodings.register(name, cls)
9273 @transfer_encodings[get_name(name)] = cls
9274 end
9275 def Encodings.defined?( str )
9276 @transfer_encodings.include? get_name(str)
9277 end
9278 def Encodings.get_encoding( str )
9279 @transfer_encodings[get_name(str)]
9280 end
9281 def Encodings.get_all
9282 @transfer_encodings.values
9283 end
9284 def Encodings.get_name(enc)
9285 underscoreize(enc).downcase
9286 end
9287 def Encodings.param_encode(str)
9288 case
9289 when str.ascii_only? && str =~ TOKEN_UNSAFE
9290 %Q{"#{str}"}
9291 when str.ascii_only?
9292 str
9293 else
9294 RubyVer.param_encode(str)
9295 end
9296 end
9297 def Encodings.param_decode(str, encoding)
9298 RubyVer.param_decode(str, encoding)
9299 end
9300 def Encodings.decode_encode(str, output_type)
9301 case
9302 when output_type == :decode
9303 Encodings.value_decode(str)
9304 else
9305 if str.ascii_only?
9306 str
9307 else
9308 Encodings.b_value_encode(str, find_encoding(str))
9309 end
9310 end
9311 end
9312 def Encodings.value_decode(str)
9313 return str unless str =~ ENCODED_VALUE
9314 lines = collapse_adjacent_encodings(str)
9315 lines.each do |line|
9316 line.gsub!(ENCODED_VALUE) do |string|
9317 case $2
9318 when *B_VALUES then b_value_decode(string)
9319 when *Q_VALUES then q_value_decode(string)
9320 end
9321 end
9322 end.join("")
9323 end
9324 output
9325 elsif to_encoding
9326 begin
9327 if RUBY_VERSION = '1.9'
9328 output.encode(to_encoding)
9329 else
9330 require 'iconv'
9331 Iconv.iconv(to_encoding, 'UTF-8', output).first
9332 end
9333 output
9334 end
9335 else
9336 output
9337 end
9338 end
9339 if address.is_a?(Array)
9340 else
9341 encode_non_usascii(address, charset) if address
9342 end
9343 end
9344 us_ascii = %Q{\x00-\x7f}
9345 tokens = address.split(/\s/)
9346 map_with_index(tokens) do |word, i|
9347 if word.ascii_only?
9348 word
9349 else
9350 word = " #{word}"
9351 end
9352 Encodings.b_value_encode(word, charset)
9353 end
9354 end.join(' ')
9355 end
9356 map_lines(string) do |str|
9357 "=?#{encoding}?B?#{str.chomp}?="
9358 end.join(" ")
9359 end
9360 map_lines(string) do |str|
9361 "=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
9362 end.join(" ")
9363 end
9364 private
9365 def Encodings.b_value_decode(str)
9366 RubyVer.b_value_decode(str)
9367 end
9368 def Encodings.q_value_decode(str)
9369 RubyVer.q_value_decode(str)
9370 end
9371 def Encodings.find_encoding(str)
9372 RUBY_VERSION = '1.9' ? str.encoding : $KCODE
9373 end
9374 def Encodings.value_encoding_from_string(str)
9375 str[ENCODED_VALUE, 1]
9376 end
9377 def Encodings.collapse_adjacent_encodings(str)
9378 results = []
9379 previous_encoding = nil
9380 lines = str.split(FULL_ENCODED_VALUE)
9381 lines.each_slice(2) do |unencoded, encoded|
9382 if encoded
9383 encoding = value_encoding_from_string(encoded)
9384 results.last encoded
9385 else
9386 results unencoded unless unencoded == EMPTY
9387 results encoded
9388 end
9389 previous_encoding = encoding
9390 else
9391 results unencoded
9392 end
9393 end
9394 results
9395 end
9396 end
9397 end
9398 module Mail
9399 class Envelope StructuredField
9400 def initialize(*args)
9401 end
9402 def element
9403 @element ||= Mail::EnvelopeFromElement.new(value)
9404 end
9405 def date
9406 ::DateTime.parse("#{element.date_time}")
9407 end
9408 def from
9409 element.address
9410 end
9411 end
9412 end
9413 require 'mail/fields'
9414 module Mail
9415 class Field
9416 include Utilities
9417 include Comparable
9418 mime-version received references reply-to
9419 resent-bcc resent-cc resent-date resent-from
9420 resent-message-id resent-sender resent-to
9421 return-path sender to ]
9422 FIELDS_MAP = {
9423 "to" = ToField,
9424 "cc" = CcField,
9425 "bcc" = BccField,
9426 "message-id" = MessageIdField,
9427 "in-reply-to" = InReplyToField,
9428 "references" = ReferencesField,
9429 "subject" = SubjectField,
9430 "comments" = CommentsField,
9431 "keywords" = KeywordsField,
9432 "date" = DateField,
9433 "from" = FromField,
9434 "sender" = SenderField,
9435 "reply-to" = ReplyToField,
9436 "resent-date" = ResentDateField,
9437 "resent-from" = ResentFromField,
9438 "resent-sender" = ResentSenderField,
9439 "resent-to" = ResentToField,
9440 "resent-cc" = ResentCcField,
9441 "resent-bcc" = ResentBccField,
9442 "resent-message-id" = ResentMessageIdField,
9443 "return-path" = ReturnPathField,
9444 "received" = ReceivedField,
9445 "mime-version" = MimeVersionField,
9446 "content-description" = ContentDescriptionField,
9447 "content-disposition" = ContentDispositionField,
9448 "content-type" = ContentTypeField,
9449 "content-id" = ContentIdField,
9450 "content-location" = ContentLocationField,
9451 }
9452 end
9453 class FieldError StandardError
9454 end
9455 class ParseError FieldError #:nodoc:
9456 attr_accessor :element, :value, :reason
9457 def initialize(element, value, reason)
9458 @element = element
9459 @value = value
9460 @reason = reason
9461 end
9462 end
9463 class SyntaxError FieldError #:nodoc:
9464 end
9465 case
9466 @charset = value.blank? ? charset : value
9467 @name = name[FIELD_PREFIX]
9468 @raw_value = name
9469 @value = nil
9470 when value.blank? # Field.new("field-name")
9471 @name = name
9472 @value = nil
9473 @raw_value = nil
9474 @charset = charset
9475 else # Field.new("field-name", "value")
9476 @name = name
9477 @value = value
9478 @raw_value = nil
9479 @charset = charset
9480 end
9481 end
9482 def field=(value)
9483 @field = value
9484 end
9485 def field
9486 @field ||= create_field(@name, @value, @charset)
9487 end
9488 def name
9489 @name
9490 end
9491 def value
9492 field.value
9493 end
9494 def value=(val)
9495 @field = create_field(name, val, @charset)
9496 end
9497 def to_s
9498 field.to_s
9499 end
9500 def inspect
9501 "#{ivar}=#{instance_variable_get(ivar).inspect}"
9502 end.join(" ")}"
9503 end
9504 def update(name, value)
9505 @field = create_field(name, value, @charset)
9506 end
9507 def same( other )
9508 match_to_s(other.name, self.name)
9509 end
9510 def responsible_for?( val )
9511 name.to_s.casecmp(val.to_s) == 0
9512 end
9513 alias_method :==, :same
9514 def =( other )
9515 self.field_order_id = other.field_order_id
9516 end
9517 def field_order_id
9518 end
9519 def method_missing(name, *args, &block)
9520 field.send(name, *args, &block)
9521 end
9522 if RUBY_VERSION = '1.9.2'
9523 end
9524 else
9525 end
9526 end
9527 FIELD_ORDER = %w[ return-path received
9528 resent-date resent-from resent-sender resent-to
9529 resent-cc resent-bcc resent-message-id
9530 date from sender reply-to to cc bcc
9531 message-id in-reply-to references
9532 subject comments keywords
9533 private
9534 def split(raw_field)
9535 rescue
9536 end
9537 def unfold(string)
9538 string.gsub(/[\r
\t]+/m, ' ')
9539 end
9540 def create_field(name, value, charset)
9541 value = unfold(value) if value.is_a?(String)
9542 begin
9543 new_field(name, value, charset)
9544 rescue Mail::Field::ParseError = e
9545 field = Mail::UnstructuredField.new(name, value)
9546 field.errors [name, value, e]
9547 field
9548 end
9549 end
9550 def new_field(name, value, charset)
9551 lower_case_name = name.to_s.downcase
9552 if field_klass = FIELDS_MAP[lower_case_name]
9553 field_klass.new(value, charset)
9554 else
9555 OptionalField.new(name, value, charset)
9556 end
9557 end
9558 end
9559 end
9560 module Mail
9561 class FieldList Array
9562 include Enumerable
9563 def ( new_field )
9564 lo = 0
9565 hi = size
9566 while lo hi
9567 mid = (lo + hi).div(2)
9568 if new_field self[mid]
9569 hi = mid
9570 else
9571 lo = mid + 1
9572 end
9573 end
9574 insert(lo, new_field)
9575 end
9576 end
9577 end
9578 require 'mail/fields/common/common_address'
9579 module Mail
9580 class BccField StructuredField
9581 include Mail::CommonAddress
9582 FIELD_NAME = 'bcc'
9583 CAPITALIZED_FIELD = 'Bcc'
9584 def initialize(value = '', charset = 'utf-8')
9585 @charset = charset
9586 self.parse
9587 self
9588 end
9589 def encoded
9590 ''
9591 end
9592 def decoded
9593 do_decode
9594 end
9595 end
9596 end
9597 require 'mail/fields/common/common_address'
9598 module Mail
9599 class CcField StructuredField
9600 include Mail::CommonAddress
9601 FIELD_NAME = 'cc'
9602 CAPITALIZED_FIELD = 'Cc'
9603 def initialize(value = nil, charset = 'utf-8')
9604 self.charset = charset
9605 self.parse
9606 self
9607 end
9608 def encoded
9609 do_encode(CAPITALIZED_FIELD)
9610 end
9611 def decoded
9612 do_decode
9613 end
9614 end
9615 end
9616 module Mail
9617 class CommentsField UnstructuredField
9618 FIELD_NAME = 'comments'
9619 CAPITALIZED_FIELD = 'Comments'
9620 def initialize(value = nil, charset = 'utf-8')
9621 @charset = charset
9622 self.parse
9623 self
9624 end
9625 end
9626 end
9627 module Mail
9628 class AddressContainer Array
9629 def initialize(field, list = [])
9630 @field = field
9631 super(list)
9632 end
9633 def (address)
9634 @field address
9635 end
9636 end
9637 end# encoding: utf-8
9638 require 'mail/fields/common/address_container'
9639 module Mail
9640 module CommonAddress # :nodoc:
9641 def parse(val = value)
9642 unless val.blank?
9643 else
9644 nil
9645 end
9646 end
9647 def charset
9648 @charset
9649 end
9650 def encode_if_needed(val)
9651 Encodings.address_encode(val, charset)
9652 end
9653 def each
9654 address_list.addresses.each do |address|
9655 yield(address)
9656 end
9657 end
9658 def addresses
9659 Mail::AddressContainer.new(self, list)
9660 end
9661 def formatted
9662 Mail::AddressContainer.new(self, list)
9663 end
9664 def display_names
9665 Mail::AddressContainer.new(self, list)
9666 end
9667 def addrs
9668 list = address_list.addresses
9669 Mail::AddressContainer.new(self, list)
9670 end
9671 def groups
9672 address_list.addresses_grouped_by_group
9673 end
9674 def group_addresses
9675 decoded_group_addresses
9676 end
9677 def decoded_group_addresses
9678 end
9679 def encoded_group_addresses
9680 end
9681 def group_names # :nodoc:
9682 address_list.group_names
9683 end
9684 def default
9685 addresses
9686 end
9687 def (val)
9688 case
9689 when val.nil?
9690 when val.blank?
9691 parse(encoded)
9692 else
9693 end
9694 end
9695 def value=(val)
9696 super
9697 parse(self.value)
9698 end
9699 private
9700 def do_encode(field_name)
9701 return '' if value.blank?
9702 address_text = address_array.join(", \r
\s")
9703 group_text = group_array.join(" \r
\s")
9704 end
9705 def do_decode
9706 return nil if value.blank?
9707 address_text = address_array.join(", ")
9708 group_text = group_array.join(" ")
9709 return_array.join(", ")
9710 end
9711 def address_list # :nodoc:
9712 @address_list ||= AddressList.new(value)
9713 end
9714 def get_group_addresses(group_list)
9715 if group_list.respond_to?(:addresses)
9716 group_list.addresses.map do |address|
9717 Mail::Address.new(address)
9718 end
9719 else
9720 []
9721 end
9722 end
9723 end
9724 end
9725 module Mail
9726 module CommonDate # :nodoc:
9727 def date_time
9728 end
9729 def default
9730 date_time
9731 end
9732 def parse(val = value)
9733 unless val.blank?
9734 @element = Mail::DateTimeElement.new(val)
9735 else
9736 nil
9737 end
9738 end
9739 private
9740 def do_encode(field_name)
9741 "#{field_name}: #{value}\r
"
9742 end
9743 def do_decode
9744 "#{value}"
9745 end
9746 def element
9747 @element ||= Mail::DateTimeElement.new(value)
9748 end
9749 end
9750 end
9751 module Mail
9752 module CommonField # :nodoc:
9753 include Mail::Constants
9754 def name=(value)
9755 @name = value
9756 end
9757 def name
9758 @name ||= nil
9759 end
9760 def value=(value)
9761 @length = nil
9762 @tree = nil
9763 @element = nil
9764 @value = value
9765 end
9766 def value
9767 @value
9768 end
9769 def to_s
9770 decoded.to_s
9771 end
9772 def default
9773 decoded
9774 end
9775 def field_length
9776 @length ||= "#{name}: #{encode(decoded)}".length
9777 end
9778 def responsible_for?( val )
9779 name.to_s.casecmp(val.to_s) == 0
9780 end
9781 private
9782 def strip_field(field_name, value)
9783 if value.is_a?(Array)
9784 value
9785 else
9786 value.to_s.sub(/#{field_name}:\s+/i, EMPTY)
9787 end
9788 end
9789 def ensure_filename_quoted(value)
9790 if value.is_a?(String)
9791 value.sub! FILENAME_RE, '\1="\2"'
9792 end
9793 end
9794 end
9795 end
9796 module Mail
9797 module CommonMessageId # :nodoc:
9798 def element
9799 end
9800 def parse(val = value)
9801 unless val.blank?
9802 @element = Mail::MessageIdsElement.new(val)
9803 else
9804 nil
9805 end
9806 end
9807 def message_id
9808 element.message_id if element
9809 end
9810 def message_ids
9811 element.message_ids if element
9812 end
9813 def default
9814 return nil unless message_ids
9815 if message_ids.length == 1
9816 message_ids[0]
9817 else
9818 message_ids
9819 end
9820 end
9821 private
9822 def do_encode(field_name)
9823 end
9824 def do_decode
9825 formated_message_ids(' ')
9826 end
9827 def formated_message_ids(join)
9828 end
9829 end
9830 end
9831 module Mail
9832 class ParameterHash IndifferentHash
9833 include Mail::Utilities
9834 def [](key_name)
9835 key_pattern = Regexp.escape(key_name.to_s)
9836 pairs = []
9837 exact = nil
9838 each do |k,v|
9839 if k =~ /^#{key_pattern}(\*|$)/i
9840 if $1 == ASTERISK
9841 pairs [k, v]
9842 else
9843 exact = k
9844 end
9845 end
9846 end
9847 super(exact || key_name)
9848 if mt = string.match(/([\w\-]+)'(\w\w)'(.*)/)
9849 string = mt[3]
9850 encoding = mt[1]
9851 else
9852 encoding = nil
9853 end
9854 Mail::Encodings.param_decode(string, encoding)
9855 end
9856 end
9857 def encoded
9858 unless value.ascii_only?
9859 value = Mail::Encodings.param_encode(value)
9860 key_name = "#{key_name}*"
9861 end
9862 %Q{#{key_name}=#{quote_token(value)}}
9863 end.join(";\r
\s")
9864 end
9865 def decoded
9866 %Q{#{key_name}=#{quote_token(value)}}
9867 end.join("; ")
9868 end
9869 end
9870 end
9871 module Mail
9872 class ContentDescriptionField UnstructuredField
9873 FIELD_NAME = 'content-description'
9874 CAPITALIZED_FIELD = 'Content-Description'
9875 def initialize(value = nil, charset = 'utf-8')
9876 self.charset = charset
9877 self.parse
9878 self
9879 end
9880 end
9881 end
9882 require 'mail/fields/common/parameter_hash'
9883 module Mail
9884 class ContentDispositionField StructuredField
9885 FIELD_NAME = 'content-disposition'
9886 CAPITALIZED_FIELD = 'Content-Disposition'
9887 def initialize(value = nil, charset = 'utf-8')
9888 self.charset = charset
9889 ensure_filename_quoted(value)
9890 self.parse
9891 self
9892 end
9893 def parse(val = value)
9894 unless val.blank?
9895 end
9896 end
9897 def element
9898 end
9899 def disposition_type
9900 element.disposition_type
9901 end
9902 def parameters
9903 @parameters = ParameterHash.new
9904 @parameters
9905 end
9906 def filename
9907 case
9908 when !parameters['filename'].blank?
9909 @filename = parameters['filename']
9910 when !parameters['name'].blank?
9911 @filename = parameters['name']
9912 else
9913 @filename = nil
9914 end
9915 @filename
9916 end
9917 def encoded
9918 if parameters.length 0
9919 p = ";\r
\s#{parameters.encoded}\r
"
9920 else
9921 p = "\r
"
9922 end
9923 "#{CAPITALIZED_FIELD}: #{disposition_type}" + p
9924 end
9925 def decoded
9926 if parameters.length 0
9927 p = "; #{parameters.decoded}"
9928 else
9929 p = ""
9930 end
9931 "#{disposition_type}" + p
9932 end
9933 end
9934 end
9935 module Mail
9936 class ContentIdField StructuredField
9937 FIELD_NAME = 'content-id'
9938 CAPITALIZED_FIELD = "Content-ID"
9939 def initialize(value = nil, charset = 'utf-8')
9940 self.charset = charset
9941 @uniq = 1
9942 if value.blank?
9943 value = generate_content_id
9944 else
9945 value = strip_field(FIELD_NAME, value)
9946 end
9947 self.parse
9948 self
9949 end
9950 def parse(val = value)
9951 unless val.blank?
9952 @element = Mail::MessageIdsElement.new(val)
9953 end
9954 end
9955 def element
9956 @element ||= Mail::MessageIdsElement.new(value)
9957 end
9958 def name
9959 'Content-ID'
9960 end
9961 def content_id
9962 element.message_id
9963 end
9964 def to_s
9965 "#{content_id}"
9966 end
9967 def encoded
9968 "#{CAPITALIZED_FIELD}: #{to_s}\r
"
9969 end
9970 def decoded
9971 "#{to_s}"
9972 end
9973 private
9974 def generate_content_id
9975 "#{Mail.random_tag}@#{::Socket.gethostname}.mail"
9976 end
9977 end
9978 end
9979 module Mail
9980 class ContentLocationField StructuredField
9981 FIELD_NAME = 'content-location'
9982 CAPITALIZED_FIELD = 'Content-Location'
9983 def initialize(value = nil, charset = 'utf-8')
9984 self.charset = charset
9985 self.parse
9986 self
9987 end
9988 def parse(val = value)
9989 unless val.blank?
9990 @element = Mail::ContentLocationElement.new(val)
9991 end
9992 end
9993 def element
9994 end
9995 def location
9996 element.location
9997 end
9998 def encoded
9999 "#{CAPITALIZED_FIELD}: #{location}\r
"
10000 end
10001 def decoded
10002 location
10003 end
10004 end
10005 end
10006 module Mail
10007 FIELD_NAME = 'content-transfer-encoding'
10008 CAPITALIZED_FIELD = 'Content-Transfer-Encoding'
10009 def initialize(value = nil, charset = 'utf-8')
10010 self.charset = charset
10011 value = '7bit' if value.to_s =~ /7-?bits?/i
10012 value = '8bit' if value.to_s =~ /8-?bits?/i
10013 self.parse
10014 self
10015 end
10016 def parse(val = value)
10017 unless val.blank?
10018 end
10019 end
10020 def element
10021 end
10022 def encoding
10023 element.encoding
10024 end
10025 def encoded
10026 "#{CAPITALIZED_FIELD}: #{encoding}\r
"
10027 end
10028 def decoded
10029 encoding
10030 end
10031 end
10032 end
10033 require 'mail/fields/common/parameter_hash'
10034 module Mail
10035 class ContentTypeField StructuredField
10036 FIELD_NAME = 'content-type'
10037 CAPITALIZED_FIELD = 'Content-Type'
10038 def initialize(value = nil, charset = 'utf-8')
10039 self.charset = charset
10040 if value.class == Array
10041 @main_type = value[0]
10042 @sub_type = value[1]
10043 else
10044 @main_type = nil
10045 @sub_type = nil
10046 @parameters = nil
10047 value = strip_field(FIELD_NAME, value)
10048 end
10049 ensure_filename_quoted(value)
10050 super(CAPITALIZED_FIELD, value, charset)
10051 self.parse
10052 self
10053 end
10054 def parse(val = value)
10055 unless val.blank?
10056 self.value = val
10057 @element = nil
10058 element
10059 end
10060 end
10061 def element
10062 begin
10063 @element ||= Mail::ContentTypeElement.new(value)
10064 rescue
10065 attempt_to_clean
10066 end
10067 end
10068 def attempt_to_clean
10069 rescue
10070 end
10071 def main_type
10072 @main_type ||= element.main_type
10073 end
10074 def sub_type
10075 @sub_type ||= element.sub_type
10076 end
10077 def string
10078 "#{main_type}/#{sub_type}"
10079 end
10080 def default
10081 decoded
10082 end
10083 alias :content_type :string
10084 def parameters
10085 unless @parameters
10086 @parameters = ParameterHash.new
10087 end
10088 @parameters
10089 end
10090 def ContentTypeField.with_boundary(type)
10091 new("#{type}; boundary=#{generate_boundary}")
10092 end
10093 def ContentTypeField.generate_boundary
10094 "--==_mimepart_#{Mail.random_tag}"
10095 end
10096 def value
10097 if @value.class == Array
10098 else
10099 @value
10100 end
10101 end
10102 def stringify(params)
10103 end
10104 def filename
10105 case
10106 when parameters['filename']
10107 @filename = parameters['filename']
10108 when parameters['name']
10109 @filename = parameters['name']
10110 else
10111 @filename = nil
10112 end
10113 @filename
10114 end
10115 def encoded
10116 if parameters.length 0
10117 p = ";\r
\s#{parameters.encoded}"
10118 else
10119 p = ""
10120 end
10121 "#{CAPITALIZED_FIELD}: #{content_type}#{p}\r
"
10122 end
10123 def decoded
10124 if parameters.length 0
10125 p = "; #{parameters.decoded}"
10126 else
10127 p = ""
10128 end
10129 "#{content_type}" + p
10130 end
10131 private
10132 def method_missing(name, *args, &block)
10133 if name.to_s =~ /(\w+)=/
10134 self.parameters[$1] = args.first
10135 else
10136 super
10137 end
10138 end
10139 def sanatize( val )
10140 val = val.
10141 tr(' ',';').
10142 squeeze(';').
10143 if val =~ /(boundary=(\S*))/i
10144 else
10145 val.downcase!
10146 end
10147 case
10148 "#{$1}/#{$2}; #{$3}"
10149 "#{$1}/#{$2}; charset=#{quote_atom($3)}"
10150 when val.chomp =~ /^text;?$/i
10151 "text/plain;"
10152 when val.chomp =~ /^(\w+);\s(.*)$/i
10153 "text/plain; #{$2}"
10154 "#{$1}; charset=#{quote_atom($2)}"
10155 when val =~ /([\w\-]+\/[\w\-]+);\s+(.*)/i
10156 type = $1
10157 params = $2.to_s.split(/\s+/)
10158 params = params.map { |i| i.to_s.chomp.strip }
10159 params = params.map { |i| i.split(/\s*\=\s*/) }
10160 "#{type}; #{params}"
10161 when val =~ /^\s*$/
10162 'text/plain'
10163 else
10164 ''
10165 end
10166 end
10167 def get_mime_type( val )
10168 case
10169 when val =~ /^([\w\-]+)\/([\w\-]+);.+$/i
10170 "#{$1}/#{$2}"
10171 else
10172 'text/plain'
10173 end
10174 end
10175 end
10176 end
10177 require 'mail/fields/common/common_date'
10178 module Mail
10179 class DateField StructuredField
10180 include Mail::CommonDate
10181 FIELD_NAME = 'date'
10182 CAPITALIZED_FIELD = "Date"
10183 def initialize(value = nil, charset = 'utf-8')
10184 self.charset = charset
10185 if value.blank?
10186 else
10187 value = strip_field(FIELD_NAME, value)
10188 value.to_s.gsub!(/\(.*?\)/, '')
10189 end
10190 super(CAPITALIZED_FIELD, value, charset)
10191 rescue ArgumentError = e
10192 raise e unless "invalid date"==e.message
10193 end
10194 def encoded
10195 do_encode(CAPITALIZED_FIELD)
10196 end
10197 def decoded
10198 do_decode
10199 end
10200 end
10201 end
10202 require 'mail/fields/common/common_address'
10203 module Mail
10204 class FromField StructuredField
10205 include Mail::CommonAddress
10206 FIELD_NAME = 'from'
10207 CAPITALIZED_FIELD = 'From'
10208 def initialize(value = nil, charset = 'utf-8')
10209 self.charset = charset
10210 self.parse
10211 self
10212 end
10213 def encoded
10214 do_encode(CAPITALIZED_FIELD)
10215 end
10216 def decoded
10217 do_decode
10218 end
10219 end
10220 end
10221 require 'mail/fields/common/common_message_id'
10222 module Mail
10223 class InReplyToField StructuredField
10224 include Mail::CommonMessageId
10225 FIELD_NAME = 'in-reply-to'
10226 CAPITALIZED_FIELD = 'In-Reply-To'
10227 def initialize(value = nil, charset = 'utf-8')
10228 self.charset = charset
10229 self.parse
10230 self
10231 end
10232 def encoded
10233 do_encode(CAPITALIZED_FIELD)
10234 end
10235 def decoded
10236 do_decode
10237 end
10238 end
10239 end
10240 module Mail
10241 class KeywordsField StructuredField
10242 FIELD_NAME = 'keywords'
10243 CAPITALIZED_FIELD = 'Keywords'
10244 def initialize(value = nil, charset = 'utf-8')
10245 self.charset = charset
10246 self.parse
10247 self
10248 end
10249 def parse(val = value)
10250 unless val.blank?
10251 @phrase_list ||= PhraseList.new(value)
10252 end
10253 end
10254 def phrase_list
10255 @phrase_list ||= PhraseList.new(value)
10256 end
10257 def keywords
10258 phrase_list.phrases
10259 end
10260 def encoded
10261 end
10262 def decoded
10263 keywords.join(', ')
10264 end
10265 def default
10266 keywords
10267 end
10268 end
10269 end
10270 require 'mail/fields/common/common_message_id'
10271 module Mail
10272 class MessageIdField StructuredField
10273 include Mail::CommonMessageId
10274 FIELD_NAME = 'message-id'
10275 CAPITALIZED_FIELD = 'Message-ID'
10276 def initialize(value = nil, charset = 'utf-8')
10277 self.charset = charset
10278 @uniq = 1
10279 if value.blank?
10280 self.name = CAPITALIZED_FIELD
10281 self.value = generate_message_id
10282 else
10283 end
10284 self.parse
10285 self
10286 end
10287 def name
10288 'Message-ID'
10289 end
10290 def message_ids
10291 [message_id]
10292 end
10293 def to_s
10294 "#{message_id}"
10295 end
10296 def encoded
10297 do_encode(CAPITALIZED_FIELD)
10298 end
10299 def decoded
10300 do_decode
10301 end
10302 private
10303 def generate_message_id
10304 "#{Mail.random_tag}@#{::Socket.gethostname}.mail"
10305 end
10306 end
10307 end
10308 module Mail
10309 class MimeVersionField StructuredField
10310 FIELD_NAME = 'mime-version'
10311 CAPITALIZED_FIELD = 'Mime-Version'
10312 def initialize(value = nil, charset = 'utf-8')
10313 self.charset = charset
10314 if value.blank?
10315 value = '1.0'
10316 end
10317 self.parse
10318 self
10319 end
10320 def parse(val = value)
10321 unless val.blank?
10322 @element = Mail::MimeVersionElement.new(val)
10323 end
10324 end
10325 def element
10326 @element ||= Mail::MimeVersionElement.new(value)
10327 end
10328 def version
10329 "#{element.major}.#{element.minor}"
10330 end
10331 def major
10332 element.major.to_i
10333 end
10334 def minor
10335 element.minor.to_i
10336 end
10337 def encoded
10338 "#{CAPITALIZED_FIELD}: #{version}\r
"
10339 end
10340 def decoded
10341 version
10342 end
10343 end
10344 end
10345 require 'mail/fields/unstructured_field'
10346 module Mail
10347 class OptionalField UnstructuredField
10348 end
10349 end
10350 module Mail
10351 class ReceivedField StructuredField
10352 FIELD_NAME = 'received'
10353 CAPITALIZED_FIELD = 'Received'
10354 def initialize(value = nil, charset = 'utf-8')
10355 self.charset = charset
10356 self.parse
10357 self
10358 end
10359 def parse(val = value)
10360 unless val.blank?
10361 @element = Mail::ReceivedElement.new(val)
10362 end
10363 end
10364 def element
10365 @element ||= Mail::ReceivedElement.new(value)
10366 end
10367 def date_time
10368 end
10369 def info
10370 element.info
10371 end
10372 def formatted_date
10373 end
10374 def encoded
10375 if value.blank?
10376 "#{CAPITALIZED_FIELD}: \r
"
10377 else
10378 end
10379 end
10380 def decoded
10381 if value.blank?
10382 ""
10383 else
10384 "#{info}; #{formatted_date}"
10385 end
10386 end
10387 end
10388 end
10389 require 'mail/fields/common/common_message_id'
10390 module Mail
10391 class ReferencesField StructuredField
10392 include CommonMessageId
10393 FIELD_NAME = 'references'
10394 CAPITALIZED_FIELD = 'References'
10395 def initialize(value = nil, charset = 'utf-8')
10396 self.charset = charset
10397 self.parse
10398 self
10399 end
10400 def encoded
10401 do_encode(CAPITALIZED_FIELD)
10402 end
10403 def decoded
10404 do_decode
10405 end
10406 end
10407 end
10408 require 'mail/fields/common/common_address'
10409 module Mail
10410 class ReplyToField StructuredField
10411 include Mail::CommonAddress
10412 FIELD_NAME = 'reply-to'
10413 CAPITALIZED_FIELD = 'Reply-To'
10414 def initialize(value = nil, charset = 'utf-8')
10415 self.charset = charset
10416 self.parse
10417 self
10418 end
10419 def encoded
10420 do_encode(CAPITALIZED_FIELD)
10421 end
10422 def decoded
10423 do_decode
10424 end
10425 end
10426 end
10427 require 'mail/fields/common/common_address'
10428 module Mail
10429 class ResentBccField StructuredField
10430 include Mail::CommonAddress
10431 FIELD_NAME = 'resent-bcc'
10432 CAPITALIZED_FIELD = 'Resent-Bcc'
10433 def initialize(value = nil, charset = 'utf-8')
10434 self.charset = charset
10435 self.parse
10436 self
10437 end
10438 def encoded
10439 do_encode(CAPITALIZED_FIELD)
10440 end
10441 def decoded
10442 do_decode
10443 end
10444 end
10445 end
10446 require 'mail/fields/common/common_address'
10447 module Mail
10448 class ResentCcField StructuredField
10449 include Mail::CommonAddress
10450 FIELD_NAME = 'resent-cc'
10451 CAPITALIZED_FIELD = 'Resent-Cc'
10452 def initialize(value = nil, charset = 'utf-8')
10453 self.charset = charset
10454 self.parse
10455 self
10456 end
10457 def encoded
10458 do_encode(CAPITALIZED_FIELD)
10459 end
10460 def decoded
10461 do_decode
10462 end
10463 end
10464 end
10465 require 'mail/fields/common/common_date'
10466 module Mail
10467 class ResentDateField StructuredField
10468 include Mail::CommonDate
10469 FIELD_NAME = 'resent-date'
10470 CAPITALIZED_FIELD = 'Resent-Date'
10471 def initialize(value = nil, charset = 'utf-8')
10472 self.charset = charset
10473 if value.blank?
10474 else
10475 value = strip_field(FIELD_NAME, value)
10476 end
10477 super(CAPITALIZED_FIELD, value, charset)
10478 self
10479 end
10480 def encoded
10481 do_encode(CAPITALIZED_FIELD)
10482 end
10483 def decoded
10484 do_decode
10485 end
10486 end
10487 end
10488 require 'mail/fields/common/common_address'
10489 module Mail
10490 class ResentFromField StructuredField
10491 include Mail::CommonAddress
10492 FIELD_NAME = 'resent-from'
10493 CAPITALIZED_FIELD = 'Resent-From'
10494 def initialize(value = nil, charset = 'utf-8')
10495 self.charset = charset
10496 self.parse
10497 self
10498 end
10499 def encoded
10500 do_encode(CAPITALIZED_FIELD)
10501 end
10502 def decoded
10503 do_decode
10504 end
10505 end
10506 end
10507 require 'mail/fields/common/common_message_id'
10508 module Mail
10509 class ResentMessageIdField StructuredField
10510 include CommonMessageId
10511 FIELD_NAME = 'resent-message-id'
10512 CAPITALIZED_FIELD = 'Resent-Message-ID'
10513 def initialize(value = nil, charset = 'utf-8')
10514 self.charset = charset
10515 self.parse
10516 self
10517 end
10518 def name
10519 'Resent-Message-ID'
10520 end
10521 def encoded
10522 do_encode(CAPITALIZED_FIELD)
10523 end
10524 def decoded
10525 do_decode
10526 end
10527 end
10528 end
10529 require 'mail/fields/common/common_address'
10530 module Mail
10531 class ResentSenderField StructuredField
10532 include Mail::CommonAddress
10533 FIELD_NAME = 'resent-sender'
10534 CAPITALIZED_FIELD = 'Resent-Sender'
10535 def initialize(value = nil, charset = 'utf-8')
10536 self.charset = charset
10537 self.parse
10538 self
10539 end
10540 def addresses
10541 [address.address]
10542 end
10543 def address
10544 address_list.addresses.first
10545 end
10546 def encoded
10547 do_encode(CAPITALIZED_FIELD)
10548 end
10549 def decoded
10550 do_decode
10551 end
10552 end
10553 end
10554 require 'mail/fields/common/common_address'
10555 module Mail
10556 class ResentToField StructuredField
10557 include Mail::CommonAddress
10558 FIELD_NAME = 'resent-to'
10559 CAPITALIZED_FIELD = 'Resent-To'
10560 def initialize(value = nil, charset = 'utf-8')
10561 self.charset = charset
10562 self.parse
10563 self
10564 end
10565 def encoded
10566 do_encode(CAPITALIZED_FIELD)
10567 end
10568 def decoded
10569 do_decode
10570 end
10571 end
10572 end
10573 require 'mail/fields/common/common_address'
10574 module Mail
10575 class ReturnPathField StructuredField
10576 include Mail::CommonAddress
10577 FIELD_NAME = 'return-path'
10578 CAPITALIZED_FIELD = 'Return-Path'
10579 def initialize(value = nil, charset = 'utf-8')
10580 value = nil if value == ''
10581 self.charset = charset
10582 self.parse
10583 self
10584 end
10585 def encoded
10586 "#{CAPITALIZED_FIELD}: #{address}\r
"
10587 end
10588 def decoded
10589 do_decode
10590 end
10591 def address
10592 addresses.first
10593 end
10594 def default
10595 address
10596 end
10597 end
10598 end
10599 require 'mail/fields/common/common_address'
10600 module Mail
10601 class SenderField StructuredField
10602 include Mail::CommonAddress
10603 FIELD_NAME = 'sender'
10604 CAPITALIZED_FIELD = 'Sender'
10605 def initialize(value = nil, charset = 'utf-8')
10606 self.charset = charset
10607 self.parse
10608 self
10609 end
10610 def addresses
10611 [address.address]
10612 end
10613 def address
10614 address_list.addresses.first
10615 end
10616 def encoded
10617 do_encode(CAPITALIZED_FIELD)
10618 end
10619 def decoded
10620 do_decode
10621 end
10622 def default
10623 address.address
10624 end
10625 end
10626 end
10627 require 'mail/fields/common/common_field'
10628 module Mail
10629 class StructuredField
10630 include Mail::CommonField
10631 include Mail::Utilities
10632 self.name = name
10633 self.value = value
10634 self.charset = charset
10635 self
10636 end
10637 def charset
10638 @charset
10639 end
10640 def charset=(val)
10641 @charset = val
10642 end
10643 def default
10644 decoded
10645 end
10646 def errors
10647 []
10648 end
10649 end
10650 end
10651 module Mail
10652 class SubjectField UnstructuredField
10653 FIELD_NAME = 'subject'
10654 CAPITALIZED_FIELD = "Subject"
10655 def initialize(value = nil, charset = 'utf-8')
10656 self.charset = charset
10657 end
10658 end
10659 end
10660 require 'mail/fields/common/common_address'
10661 module Mail
10662 class ToField StructuredField
10663 include Mail::CommonAddress
10664 FIELD_NAME = 'to'
10665 CAPITALIZED_FIELD = 'To'
10666 def initialize(value = nil, charset = 'utf-8')
10667 self.charset = charset
10668 self.parse
10669 self
10670 end
10671 def encoded
10672 do_encode(CAPITALIZED_FIELD)
10673 end
10674 def decoded
10675 do_decode
10676 end
10677 end
10678 end
10679 require 'mail/fields/common/common_field'
10680 module Mail
10681 class UnstructuredField
10682 include Mail::CommonField
10683 include Mail::Utilities
10684 attr_accessor :charset
10685 attr_reader :errors
10686 def initialize(name, value, charset = nil)
10687 @errors = []
10688 if value.is_a?(Array)
10689 value = value.join(', ')
10690 else
10691 value = value.to_s
10692 end
10693 if charset
10694 self.charset = charset
10695 else
10696 if value.respond_to?(:encoding)
10697 self.charset = value.encoding
10698 else
10699 self.charset = $KCODE
10700 end
10701 end
10702 self.name = name
10703 self.value = value
10704 self
10705 end
10706 def encoded
10707 do_encode
10708 end
10709 def decoded
10710 do_decode
10711 end
10712 def default
10713 decoded
10714 end
10715 def parse # An unstructured field does not parse
10716 self
10717 end
10718 private
10719 def do_encode
10720 value.nil? ? '' : "#{wrapped_value}\r
"
10721 end
10722 def do_decode
10723 end
10724 def wrapped_value # :nodoc:
10725 wrap_lines(name, fold("#{name}: ".length))
10726 end
10727 def wrap_lines(name, folded_lines)
10728 result = ["#{name}: #{folded_lines.shift}"]
10729 result.concat(folded_lines)
10730 result.join("\r
\s")
10731 end
10732 def fold(prepend = 0) # :nodoc:
10733 encoding = normalized_encoding
10734 decoded_string = decoded.to_s
10735 should_encode = decoded_string.not_ascii_only?
10736 if should_encode
10737 first = true
10738 if first
10739 first = !first
10740 else
10741 word = " " word
10742 end
10743 if word.not_ascii_only?
10744 word
10745 else
10746 word.scan(/.{7}|.+$/)
10747 end
10748 end.flatten
10749 else
10750 words = decoded_string.split(/[ \t]/)
10751 end
10752 folded_lines = []
10753 while !words.empty?
10754 limit = 78 - prepend
10755 line = ""
10756 first_word = true
10757 while !words.empty?
10758 break unless word = words.first.dup
10759 word = encode(word) if should_encode
10760 word = encode_crlf(word)
10761 words.shift
10762 if first_word
10763 first_word = false
10764 else
10765 line " " if !should_encode
10766 end
10767 line word
10768 end
10769 folded_lines line
10770 prepend = 0
10771 end
10772 folded_lines
10773 end
10774 def encode(value)
10775 value.gsub!(/"/, '=22')
10776 value.gsub!(/\(/, '=28')
10777 value.gsub!(/\)/, '=29')
10778 value.gsub!(/\?/, '=3F')
10779 value.gsub!(/_/, '=5F')
10780 value.gsub!(/ /, '_')
10781 value
10782 end
10783 def encode_crlf(value)
10784 value.gsub!(CR, CR_ENCODED)
10785 value.gsub!(LF, LF_ENCODED)
10786 value
10787 end
10788 def normalized_encoding
10789 encoding = charset.to_s.upcase.gsub('_', '-')
10790 encoding
10791 end
10792 end
10793 end
10794 module Mail
10795 end
10796 module Mail
10797 class Header
10798 include Constants
10799 include Utilities
10800 include Enumerable
10801 @@maximum_amount = 1000
10802 def self.maximum_amount
10803 @@maximum_amount
10804 end
10805 def self.maximum_amount=(value)
10806 @@maximum_amount = value
10807 end
10808 def initialize(header_text = nil, charset = nil)
10809 @charset = charset
10810 self.raw_source = header_text.to_crlf.lstrip
10811 split_header if header_text
10812 end
10813 def initialize_copy(original)
10814 super
10815 @fields = @fields.dup
10816 end
10817 def raw_source
10818 @raw_source
10819 end
10820 def fields
10821 @fields ||= FieldList.new
10822 end
10823 def fields=(unfolded_fields)
10824 @fields = Mail::FieldList.new
10825 field = Field.new(field, nil, charset)
10826 selected.first.update(field.name, field.value)
10827 else
10828 @fields field
10829 end
10830 end
10831 end
10832 def errors
10833 @fields.map(&:errors).flatten(1)
10834 end
10835 def [](name)
10836 name = dasherize(name)
10837 name.downcase!
10838 selected = select_field_for(name)
10839 case
10840 when selected.length 1
10841 selected.map { |f| f }
10842 when !selected.blank?
10843 selected.first
10844 else
10845 nil
10846 end
10847 end
10848 def []=(name, value)
10849 name = dasherize(name)
10850 if name.include?(':')
10851 end
10852 fn = name.downcase
10853 selected = select_field_for(fn)
10854 case
10855 when !selected.blank? && value == nil
10856 fields.delete_if { |f| selected.include?(f) }
10857 when !selected.blank? && limited_field?(fn)
10858 selected.first.update(fn, value)
10859 else
10860 self.fields Field.new(name.to_s, value, charset)
10861 end
10862 if dasherize(fn) == "content-type"
10863 end
10864 end
10865 def charset
10866 @charset
10867 end
10868 def charset=(val)
10869 if params
10870 params[:charset] = val
10871 end
10872 @charset = val
10873 end
10874 message-id in-reply-to references subject
10875 return-path content-type mime-version
10876 content-transfer-encoding content-description
10877 content-id content-disposition content-location]
10878 def encoded
10879 buffer = ''
10880 fields.each do |field|
10881 buffer field.encoded
10882 end
10883 buffer
10884 end
10885 def to_s
10886 encoded
10887 end
10888 def decoded
10889 end
10890 def field_summary
10891 end
10892 def has_message_id?
10893 end
10894 def has_content_id?
10895 end
10896 def has_date?
10897 end
10898 def has_mime_version?
10899 end
10900 private
10901 def raw_source=(val)
10902 @raw_source = val
10903 end
10904 def split_header
10905 self.fields = raw_source.split(HEADER_SPLIT)
10906 end
10907 def select_field_for(name)
10908 fields.select { |f| f.responsible_for?(name) }
10909 end
10910 def limited_field?(name)
10911 LIMITED_FIELDS.include?(name.to_s.downcase)
10912 end
10913 def each( &block )
10914 return self.fields.each( &block ) if block
10915 self.fields.each
10916 end
10917 end
10918 end
10919 module Mail
10920 class IndifferentHash Hash
10921 def initialize(constructor = {})
10922 if constructor.is_a?(Hash)
10923 super()
10924 update(constructor)
10925 else
10926 super(constructor)
10927 end
10928 end
10929 def default(key = nil)
10930 if key.is_a?(Symbol) && include?(key = key.to_s)
10931 self[key]
10932 else
10933 super
10934 end
10935 end
10936 def self.new_from_hash_copying_default(hash)
10937 IndifferentHash.new(hash).tap do |new_hash|
10938 new_hash.default = hash.default
10939 end
10940 end
10941 def []=(key, value)
10942 end
10943 alias_method :store, :[]=
10944 def update(other_hash)
10945 self
10946 end
10947 alias_method :merge!, :update
10948 def key?(key)
10949 super(convert_key(key))
10950 end
10951 alias_method :include?, :key?
10952 alias_method :has_key?, :key?
10953 alias_method :member?, :key?
10954 def fetch(key, *extras)
10955 super(convert_key(key), *extras)
10956 end
10957 def values_at(*indices)
10958 indices.collect {|key| self[convert_key(key)]}
10959 end
10960 def dup
10961 IndifferentHash.new(self)
10962 end
10963 def merge(hash)
10964 self.dup.update(hash)
10965 end
10966 def reverse_merge(other_hash)
10967 end
10968 def reverse_merge!(other_hash)
10969 replace(reverse_merge( other_hash ))
10970 end
10971 def delete(key)
10972 super(convert_key(key))
10973 end
10974 def stringify_keys!; self end
10975 def stringify_keys; dup end
10976 def symbolize_keys; to_hash.symbolize_keys end
10977 def to_options!; self end
10978 def to_hash
10979 Hash.new(default).merge!(self)
10980 end
10981 protected
10982 def convert_key(key)
10983 key.kind_of?(Symbol) ? key.to_s : key
10984 end
10985 def convert_value(value)
10986 if value.class == Hash
10987 self.class.new_from_hash_copying_default(value)
10988 elsif value.is_a?(Array)
10989 else
10990 value
10991 end
10992 end
10993 end
10994 end
10995 module Mail
10996 def self.new(*args, &block)
10997 Message.new(args, &block)
10998 end
10999 def self.defaults(&block)
11000 Configuration.instance.instance_eval(&block)
11001 end
11002 def self.delivery_method
11003 Configuration.instance.delivery_method
11004 end
11005 def self.retriever_method
11006 Configuration.instance.retriever_method
11007 end
11008 def self.deliver(*args, &block)
11009 mail = self.new(args, &block)
11010 mail.deliver
11011 mail
11012 end
11013 def self.find(*args, &block)
11014 retriever_method.find(*args, &block)
11015 end
11016 def self.find_and_delete(*args, &block)
11017 retriever_method.find_and_delete(*args, &block)
11018 end
11019 def self.first(*args, &block)
11020 retriever_method.first(*args, &block)
11021 end
11022 def self.last(*args, &block)
11023 retriever_method.last(*args, &block)
11024 end
11025 def self.all(*args, &block)
11026 retriever_method.all(*args, &block)
11027 end
11028 def self.read(filename)
11029 end
11030 def self.delete_all(*args, &block)
11031 retriever_method.delete_all(*args, &block)
11032 end
11033 def Mail.read_from_string(mail_as_string)
11034 Mail.new(mail_as_string)
11035 end
11036 def Mail.connection(&block)
11037 retriever_method.connection(&block)
11038 end
11039 @@delivery_notification_observers = []
11040 @@delivery_interceptors = []
11041 def self.register_observer(observer)
11042 @@delivery_notification_observers observer
11043 end
11044 end
11045 def self.unregister_observer(observer)
11046 end
11047 def self.register_interceptor(interceptor)
11048 @@delivery_interceptors interceptor
11049 end
11050 end
11051 def self.unregister_interceptor(interceptor)
11052 @@delivery_interceptors.delete(interceptor)
11053 end
11054 def self.inform_observers(mail)
11055 observer.delivered_email(mail)
11056 end
11057 end
11058 def self.inform_interceptors(mail)
11059 @@delivery_interceptors.each do |interceptor|
11060 interceptor.delivering_email(mail)
11061 end
11062 end
11063 protected
11064 RANDOM_TAG='%x%x_%x%x%d%x'
11065 def self.random_tag
11066 t = Time.now
11067 sprintf(RANDOM_TAG,
11068 t.to_i, t.tv_usec,
11069 end
11070 private
11071 def self.something_random
11072 end
11073 def self.uniq
11074 @@uniq += 1
11075 end
11076 @@uniq = self.something_random
11077 end
11078 module Mail
11079 module Matchers
11080 def have_sent_email
11081 HasSentEmailMatcher.new(self)
11082 end
11083 class HasSentEmailMatcher
11084 def initialize(_context)
11085 end
11086 def matches?(subject)
11087 !(matching_deliveries.empty?)
11088 end
11089 def from(sender)
11090 @sender = sender
11091 self
11092 end
11093 def to(recipient_or_list)
11094 @recipients ||= []
11095 if recipient_or_list.kind_of?(Array)
11096 @recipients += recipient_or_list
11097 else
11098 @recipients recipient_or_list
11099 end
11100 self
11101 end
11102 def cc(recipient_or_list)
11103 @copy_recipients ||= []
11104 if recipient_or_list.kind_of?(Array)
11105 @copy_recipients += recipient_or_list
11106 else
11107 @copy_recipients recipient_or_list
11108 end
11109 self
11110 end
11111 def bcc(recipient_or_list)
11112 @blind_copy_recipients ||= []
11113 if recipient_or_list.kind_of?(Array)
11114 @blind_copy_recipients += recipient_or_list
11115 else
11116 @blind_copy_recipients recipient_or_list
11117 end
11118 self
11119 end
11120 def with_subject(subject)
11121 @subject = subject
11122 self
11123 end
11124 def matching_subject(subject_matcher)
11125 @subject_matcher = subject_matcher
11126 self
11127 end
11128 def with_body(body)
11129 @body = body
11130 self
11131 end
11132 def matching_body(body_matcher)
11133 @body_matcher = body_matcher
11134 self
11135 end
11136 def description
11137 result = "send a matching email"
11138 result
11139 end
11140 def failure_message
11141 result = "Expected email to be sent "
11142 result += explain_expectations
11143 result += dump_deliveries
11144 result
11145 end
11146 def failure_message_when_negated
11147 result = "Expected no email to be sent "
11148 result += explain_expectations
11149 result += dump_deliveries
11150 result
11151 end
11152 protected
11153 def filter_matched_deliveries(deliveries)
11154 candidate_deliveries = deliveries
11155 end
11156 candidate_deliveries
11157 end
11158 def matches_on_sender?(delivery)
11159 delivery.from.include?(@sender)
11160 end
11161 def matches_on_recipients?(delivery)
11162 end
11163 def matches_on_copy_recipients?(delivery)
11164 end
11165 def matches_on_blind_copy_recipients?(delivery)
11166 end
11167 def matches_on_subject?(delivery)
11168 delivery.subject == @subject
11169 end
11170 def matches_on_subject_matcher?(delivery)
11171 @subject_matcher.match delivery.subject
11172 end
11173 def matches_on_body?(delivery)
11174 delivery.body == @body
11175 end
11176 def matches_on_body_matcher?(delivery)
11177 @body_matcher.match delivery.body.raw_source
11178 end
11179 def explain_expectations
11180 result = ''
11181 result
11182 end
11183 def dump_deliveries
11184 end
11185 end
11186 end
11187 end
11188 require "yaml"
11189 module Mail
11190 class Message
11191 include Constants
11192 include Utilities
11193 def initialize(*args, &block)
11194 @body = nil
11195 @body_raw = nil
11196 @separate_parts = false
11197 @text_part = nil
11198 @html_part = nil
11199 @errors = nil
11200 @header = nil
11201 @charset = self.class.default_charset
11202 @defaulted_charset = true
11203 @smtp_envelope_from = nil
11204 @smtp_envelope_to = nil
11205 @perform_deliveries = true
11206 @raise_delivery_errors = true
11207 @delivery_handler = nil
11208 @delivery_method = Mail.delivery_method.dup
11209 @mark_for_delete = false
11210 if args.flatten.first.respond_to?(:each_pair)
11211 init_with_hash(args.flatten.first)
11212 else
11213 init_with_string(args.flatten[0].to_s)
11214 end
11215 if block_given?
11216 instance_eval(&block)
11217 end
11218 self
11219 end
11220 attr_accessor :delivery_handler
11221 attr_accessor :perform_deliveries
11222 attr_accessor :raise_delivery_errors
11223 def self.default_charset; @@default_charset; end
11224 self.default_charset = 'UTF-8'
11225 def register_for_delivery_notification(observer)
11226 Mail.register_observer(observer)
11227 end
11228 def inform_observers
11229 Mail.inform_observers(self)
11230 end
11231 def inform_interceptors
11232 Mail.inform_interceptors(self)
11233 end
11234 def deliver
11235 inform_interceptors
11236 if delivery_handler
11237 else
11238 do_delivery
11239 end
11240 inform_observers
11241 self
11242 end
11243 def deliver!
11244 inform_interceptors
11245 response = delivery_method.deliver!(self)
11246 inform_observers
11247 end
11248 def delivery_method(method = nil, settings = {})
11249 unless method
11250 @delivery_method
11251 else
11252 end
11253 end
11254 def reply(*args, &block)
11255 self.class.new.tap do |reply|
11256 if message_id
11257 bracketed_message_id = "#{message_id}"
11258 reply.in_reply_to = bracketed_message_id
11259 if !references.nil?
11260 refs = [references].flatten.map { |r| "#{r}" }
11261 refs bracketed_message_id
11262 reply.references = refs.join(' ')
11263 end
11264 reply.references ||= bracketed_message_id
11265 end
11266 if subject
11267 end
11268 if reply_to || from
11269 end
11270 if to
11271 reply.from = self[:to].formatted.first.to_s
11272 end
11273 unless args.empty?
11274 if args.flatten.first.respond_to?(:each_pair)
11275 reply.send(:init_with_hash, args.flatten.first)
11276 else
11277 end
11278 end
11279 if block_given?
11280 reply.instance_eval(&block)
11281 end
11282 end
11283 end
11284 def =(other)
11285 if other.nil?
11286 1
11287 else
11288 self.date = other.date
11289 end
11290 end
11291 def ==(other)
11292 return false unless other.respond_to?(:encoded)
11293 if self.message_id && other.message_id
11294 self.encoded == other.encoded
11295 else
11296 begin
11297 self.encoded == other.encoded
11298 ensure
11299 end
11300 end
11301 end
11302 def initialize_copy(original)
11303 super
11304 @header = @header.dup
11305 end
11306 def raw_source
11307 @raw_source
11308 end
11309 def set_envelope( val )
11310 @raw_envelope = val
11311 @envelope = Mail::Envelope.new( val )
11312 end
11313 def raw_envelope
11314 @raw_envelope
11315 end
11316 def envelope_from
11317 @envelope ? @envelope.from : nil
11318 end
11319 def envelope_date
11320 @envelope ? @envelope.date : nil
11321 end
11322 def header=(value)
11323 @header = Mail::Header.new(value, charset)
11324 end
11325 def header(value = nil)
11326 value ? self.header = value : @header
11327 end
11328 def headers(hash = {})
11329 hash.each_pair do |k,v|
11330 header[k] = v
11331 end
11332 end
11333 def errors
11334 header.errors
11335 end
11336 def bcc( val = nil )
11337 default :bcc, val
11338 end
11339 def bcc=( val )
11340 header[:bcc] = val
11341 end
11342 def cc( val = nil )
11343 default :cc, val
11344 end
11345 def cc=( val )
11346 header[:cc] = val
11347 end
11348 def comments( val = nil )
11349 default :comments, val
11350 end
11351 def comments=( val )
11352 header[:comments] = val
11353 end
11354 def content_description( val = nil )
11355 default :content_description, val
11356 end
11357 def content_description=( val )
11358 header[:content_description] = val
11359 end
11360 def content_disposition( val = nil )
11361 default :content_disposition, val
11362 end
11363 def content_disposition=( val )
11364 header[:content_disposition] = val
11365 end
11366 def content_id( val = nil )
11367 default :content_id, val
11368 end
11369 def content_id=( val )
11370 header[:content_id] = val
11371 end
11372 def content_location( val = nil )
11373 default :content_location, val
11374 end
11375 def content_location=( val )
11376 header[:content_location] = val
11377 end
11378 def content_transfer_encoding( val = nil )
11379 default :content_transfer_encoding, val
11380 end
11381 def content_transfer_encoding=( val )
11382 header[:content_transfer_encoding] = val
11383 end
11384 def content_type( val = nil )
11385 default :content_type, val
11386 end
11387 def content_type=( val )
11388 header[:content_type] = val
11389 end
11390 def date( val = nil )
11391 default :date, val
11392 end
11393 def date=( val )
11394 header[:date] = val
11395 end
11396 def transport_encoding( val = nil)
11397 if val
11398 self.transport_encoding = val
11399 else
11400 @transport_encoding
11401 end
11402 end
11403 def transport_encoding=( val )
11404 end
11405 def from( val = nil )
11406 default :from, val
11407 end
11408 def from=( val )
11409 header[:from] = val
11410 end
11411 def in_reply_to( val = nil )
11412 default :in_reply_to, val
11413 end
11414 def in_reply_to=( val )
11415 header[:in_reply_to] = val
11416 end
11417 def keywords( val = nil )
11418 default :keywords, val
11419 end
11420 def keywords=( val )
11421 header[:keywords] = val
11422 end
11423 def message_id( val = nil )
11424 default :message_id, val
11425 end
11426 def message_id=( val )
11427 header[:message_id] = val
11428 end
11429 def mime_version( val = nil )
11430 default :mime_version, val
11431 end
11432 def mime_version=( val )
11433 header[:mime_version] = val
11434 end
11435 def received( val = nil )
11436 if val
11437 header[:received] = val
11438 else
11439 header[:received]
11440 end
11441 end
11442 def received=( val )
11443 header[:received] = val
11444 end
11445 def references( val = nil )
11446 default :references, val
11447 end
11448 def references=( val )
11449 header[:references] = val
11450 end
11451 def reply_to( val = nil )
11452 default :reply_to, val
11453 end
11454 def reply_to=( val )
11455 header[:reply_to] = val
11456 end
11457 def resent_bcc( val = nil )
11458 default :resent_bcc, val
11459 end
11460 def resent_bcc=( val )
11461 header[:resent_bcc] = val
11462 end
11463 def resent_cc( val = nil )
11464 default :resent_cc, val
11465 end
11466 def resent_cc=( val )
11467 header[:resent_cc] = val
11468 end
11469 def resent_date( val = nil )
11470 default :resent_date, val
11471 end
11472 def resent_date=( val )
11473 header[:resent_date] = val
11474 end
11475 def resent_from( val = nil )
11476 default :resent_from, val
11477 end
11478 def resent_from=( val )
11479 header[:resent_from] = val
11480 end
11481 def resent_message_id( val = nil )
11482 default :resent_message_id, val
11483 end
11484 def resent_message_id=( val )
11485 header[:resent_message_id] = val
11486 end
11487 def resent_sender( val = nil )
11488 default :resent_sender, val
11489 end
11490 def resent_sender=( val )
11491 header[:resent_sender] = val
11492 end
11493 def resent_to( val = nil )
11494 default :resent_to, val
11495 end
11496 def resent_to=( val )
11497 header[:resent_to] = val
11498 end
11499 def return_path( val = nil )
11500 default :return_path, val
11501 end
11502 def return_path=( val )
11503 header[:return_path] = val
11504 end
11505 def sender( val = nil )
11506 default :sender, val
11507 end
11508 def sender=( val )
11509 header[:sender] = val
11510 end
11511 def smtp_envelope_from( val = nil )
11512 if val
11513 self.smtp_envelope_from = val
11514 else
11515 end
11516 end
11517 def smtp_envelope_from=( val )
11518 @smtp_envelope_from = val
11519 end
11520 def smtp_envelope_to( val = nil )
11521 if val
11522 self.smtp_envelope_to = val
11523 else
11524 @smtp_envelope_to || destinations
11525 end
11526 end
11527 def smtp_envelope_to=( val )
11528 @smtp_envelope_to =
11529 case val
11530 when Array, NilClass
11531 val
11532 else
11533 [val]
11534 end
11535 end
11536 def subject( val = nil )
11537 default :subject, val
11538 end
11539 def subject=( val )
11540 header[:subject] = val
11541 end
11542 def to( val = nil )
11543 default :to, val
11544 end
11545 def to=( val )
11546 header[:to] = val
11547 end
11548 def default( sym, val = nil )
11549 if val
11550 header[sym] = val
11551 else
11552 header[sym].default if header[sym]
11553 end
11554 end
11555 def body=(value)
11556 body_lazy(value)
11557 end
11558 def body(value = nil)
11559 if value
11560 self.body = value
11561 else
11562 process_body_raw if @body_raw
11563 @body
11564 end
11565 end
11566 def body_encoding(value)
11567 if value.nil?
11568 body.encoding
11569 else
11570 body.encoding = value
11571 end
11572 end
11573 def body_encoding=(value)
11574 body.encoding = value
11575 end
11576 def destinations
11577 [to_addrs, cc_addrs, bcc_addrs].compact.flatten
11578 end
11579 def from_addrs
11580 from ? [from].flatten : []
11581 end
11582 def to_addrs
11583 to ? [to].flatten : []
11584 end
11585 def cc_addrs
11586 cc ? [cc].flatten : []
11587 end
11588 def bcc_addrs
11589 bcc ? [bcc].flatten : []
11590 end
11591 def []=(name, value)
11592 if name.to_s == 'body'
11593 self.body = value
11594 elsif name.to_s =~ /content[-_]type/i
11595 header[name] = value
11596 elsif name.to_s == 'charset'
11597 self.charset = value
11598 else
11599 header[name] = value
11600 end
11601 end
11602 def [](name)
11603 header[underscoreize(name)]
11604 end
11605 def method_missing(name, *args, &block)
11606 field_name = underscoreize(name).chomp("=")
11607 if Mail::Field::KNOWN_FIELDS.include?(field_name)
11608 if args.empty?
11609 header[field_name]
11610 else
11611 header[field_name] = args.first
11612 end
11613 else
11614 super # otherwise pass it on
11615 end
11616 end
11617 def header_fields
11618 header.fields
11619 end
11620 def has_message_id?
11621 header.has_message_id?
11622 end
11623 def has_date?
11624 header.has_date?
11625 end
11626 def has_mime_version?
11627 header.has_mime_version?
11628 end
11629 def has_content_type?
11630 tmp = header[:content_type].main_type rescue nil
11631 !!tmp
11632 end
11633 def has_charset?
11634 tmp = header[:content_type].parameters rescue nil
11635 !!(has_content_type? && tmp && tmp['charset'])
11636 end
11637 def has_content_transfer_encoding?
11638 end
11639 def has_transfer_encoding? # :nodoc:
11640 has_content_transfer_encoding?
11641 end
11642 def add_message_id(msg_id_val = '')
11643 header['message-id'] = msg_id_val
11644 end
11645 def add_date(date_val = '')
11646 header['date'] = date_val
11647 end
11648 def add_mime_version(ver_val = '')
11649 header['mime-version'] = ver_val
11650 end
11651 def add_content_type
11652 header[:content_type] = 'text/plain'
11653 end
11654 def add_charset
11655 if !body.empty?
11656 STDERR.puts(warning)
11657 end
11658 end
11659 end
11660 def add_content_transfer_encoding
11661 if body.only_us_ascii?
11662 header[:content_transfer_encoding] = '7bit'
11663 else
11664 STDERR.puts(warning)
11665 header[:content_transfer_encoding] = '8bit'
11666 end
11667 end
11668 def add_transfer_encoding # :nodoc:
11669 add_content_transfer_encoding
11670 end
11671 def transfer_encoding # :nodoc:
11672 content_transfer_encoding
11673 end
11674 def mime_type
11675 end
11676 def message_content_type
11677 mime_type
11678 end
11679 def charset
11680 if @header
11681 else
11682 @charset
11683 end
11684 end
11685 def charset=(value)
11686 @defaulted_charset = false
11687 @charset = value
11688 @header.charset = value
11689 end
11690 def main_type
11691 end
11692 def sub_type
11693 end
11694 def mime_parameters
11695 content_type_parameters
11696 end
11697 def content_type_parameters
11698 end
11699 def multipart?
11700 end
11701 def multipart_report?
11702 multipart? && sub_type =~ /^report$/i
11703 end
11704 def delivery_status_report?
11705 end
11706 def delivery_status_part
11707 end
11708 def bounced?
11709 end
11710 def action
11711 end
11712 def final_recipient
11713 end
11714 def error_status
11715 end
11716 def diagnostic_code
11717 end
11718 def remote_mta
11719 end
11720 def retryable?
11721 end
11722 def boundary
11723 end
11724 def parts
11725 body.parts
11726 end
11727 def attachments
11728 parts.attachments
11729 end
11730 def has_attachments?
11731 !attachments.empty?
11732 end
11733 def html_part(&block)
11734 if block_given?
11735 else
11736 @html_part || find_first_mime_type('text/html')
11737 end
11738 end
11739 def text_part(&block)
11740 if block_given?
11741 else
11742 @text_part || find_first_mime_type('text/plain')
11743 end
11744 end
11745 def html_part=(msg)
11746 if msg
11747 @html_part = msg
11748 add_multipart_alternate_header if text_part
11749 add_part @html_part
11750 elsif @html_part
11751 @html_part = nil
11752 if text_part
11753 self.content_type = nil
11754 body.boundary = nil
11755 end
11756 end
11757 end
11758 def text_part=(msg)
11759 if msg
11760 @text_part = msg
11761 add_multipart_alternate_header if html_part
11762 add_part @text_part
11763 elsif @text_part
11764 @text_part = nil
11765 if html_part
11766 self.content_type = nil
11767 body.boundary = nil
11768 end
11769 end
11770 end
11771 def add_part(part)
11772 if !body.multipart? && !self.body.decoded.blank?
11773 @text_part.body = body.decoded
11774 self.body @text_part
11775 add_multipart_alternate_header
11776 end
11777 add_boundary
11778 self.body part
11779 end
11780 def part(params = {})
11781 new_part = Part.new(params)
11782 yield new_part if block_given?
11783 add_part(new_part)
11784 end
11785 def add_file(values)
11786 add_multipart_mixed_header
11787 if values.is_a?(String)
11788 basename = File.basename(values)
11789 filedata = File.open(values, 'rb') { |f| f.read }
11790 else
11791 basename = values[:filename]
11792 end
11793 self.attachments[basename] = filedata
11794 end
11795 def convert_to_multipart
11796 text = body.decoded
11797 self.body = ''
11798 :body = text})
11799 self.body text_part
11800 end
11801 def ready_to_send!
11802 identify_and_set_transfer_encoding
11803 parts.each do |part|
11804 part.transport_encoding = transport_encoding
11805 part.ready_to_send!
11806 end
11807 add_required_fields
11808 end
11809 def encode!
11810 ready_to_send!
11811 end
11812 def encoded
11813 ready_to_send!
11814 buffer = header.encoded
11815 buffer "\r
"
11816 buffer body.encoded(content_transfer_encoding)
11817 buffer
11818 end
11819 def without_attachments!
11820 return self unless has_attachments?
11821 parts.delete_if { |p| p.attachment? }
11822 body_raw = if parts.empty?
11823 ''
11824 else
11825 body.encoded
11826 end
11827 @body = Mail::Body.new(body_raw)
11828 self
11829 end
11830 def to_yaml(opts = {})
11831 hash = {}
11832 hash['headers'] = {}
11833 header.fields.each do |field|
11834 hash['headers'][field.name] = field.value
11835 end
11836 if multipart?
11837 hash['multipart_body'] = []
11838 end
11839 hash[var.to_s] = instance_variable_get(var)
11840 end
11841 hash.to_yaml(opts)
11842 end
11843 def self.from_yaml(str)
11844 hash = YAML.load(str)
11845 m = self.new(:headers = hash['headers'])
11846 hash.delete('headers')
11847 hash.each do |k,v|
11848 case
11849 when k == 'delivery_handler'
11850 begin
11851 rescue NameError
11852 end
11853 when k == 'transport_encoding'
11854 m.transport_encoding(v)
11855 when k == 'multipart_body'
11856 when k =~ /^@/
11857 m.instance_variable_set(k.to_sym, v)
11858 end
11859 end
11860 m
11861 end
11862 def self.from_hash(hash)
11863 Mail::Message.new(hash)
11864 end
11865 def to_s
11866 encoded
11867 end
11868 def inspect
11869 end
11870 def decoded
11871 case
11872 when self.text?
11873 decode_body_as_text
11874 when self.attachment?
11875 decode_body
11876 when !self.multipart?
11877 body.decoded
11878 else
11879 end
11880 end
11881 def read
11882 if self.attachment?
11883 decode_body
11884 else
11885 end
11886 end
11887 def decode_body
11888 body.decoded
11889 end
11890 def attachment?
11891 !!find_attachment
11892 end
11893 def attachment
11894 @attachment
11895 end
11896 def filename
11897 find_attachment
11898 end
11899 def all_parts
11900 parts.map { |p| [p, p.all_parts] }.flatten
11901 end
11902 def find_first_mime_type(mt)
11903 end
11904 def skip_deletion
11905 @mark_for_delete = false
11906 end
11907 def mark_for_delete=(value = true)
11908 @mark_for_delete = value
11909 end
11910 def is_marked_for_delete?
11911 return @mark_for_delete
11912 end
11913 def text?
11914 end
11915 private
11916 def parse_message
11917 self.header = header_part
11918 self.body = body_part
11919 end
11920 def raw_source=(value)
11921 @raw_source = value.to_crlf
11922 end
11923 def body_lazy(value)
11924 process_body_raw if @body_raw && value
11925 case
11926 when value == nil || value.length=0
11927 @body = Mail::Body.new('')
11928 @body_raw = nil
11929 add_encoding_to_body
11930 when @body && @body.multipart?
11931 @body Mail::Part.new(value)
11932 add_encoding_to_body
11933 else
11934 @body_raw = value
11935 end
11936 end
11937 def process_body_raw
11938 @body = Mail::Body.new(@body_raw)
11939 @body_raw = nil
11940 separate_parts if @separate_parts
11941 add_encoding_to_body
11942 end
11943 def set_envelope_header
11944 raw_string = raw_source.to_s
11945 set_envelope(match_data[1])
11946 end
11947 end
11948 def separate_parts
11949 body.split!(boundary)
11950 end
11951 def add_encoding_to_body
11952 if has_content_transfer_encoding?
11953 @body.encoding = content_transfer_encoding
11954 end
11955 end
11956 def identify_and_set_transfer_encoding
11957 if body && body.multipart?
11958 else
11959 end
11960 end
11961 def add_required_fields
11962 add_required_message_fields
11963 add_multipart_mixed_header if body.multipart?
11964 add_content_type unless has_content_type?
11965 add_charset unless has_charset?
11966 end
11967 def add_required_message_fields
11968 add_date unless has_date?
11969 add_mime_version unless has_mime_version?
11970 add_message_id unless has_message_id?
11971 end
11972 def add_multipart_alternate_header
11973 body.boundary = boundary
11974 end
11975 def add_boundary
11976 unless body.boundary && boundary
11977 body.boundary = boundary
11978 end
11979 end
11980 def add_multipart_mixed_header
11981 unless header['content-type']
11982 body.boundary = boundary
11983 end
11984 end
11985 def init_with_hash(hash)
11986 passed_in_options = IndifferentHash.new(hash)
11987 self.raw_source = ''
11988 @header = Mail::Header.new
11989 @body = Mail::Body.new
11990 @body_raw = nil
11991 body_content = nil
11992 passed_in_options.each_pair do |k,v|
11993 k = underscoreize(k).to_sym if k.class == String
11994 if k == :headers
11995 self.headers(v)
11996 elsif k == :body
11997 body_content = v
11998 else
11999 self[k] = v
12000 end
12001 end
12002 if body_content
12003 self.body = body_content
12004 if has_content_transfer_encoding?
12005 body.encoding = content_transfer_encoding
12006 end
12007 end
12008 end
12009 def init_with_string(string)
12010 self.raw_source = string
12011 set_envelope_header
12012 parse_message
12013 @separate_parts = multipart?
12014 end
12015 def find_attachment
12016 case
12017 when content_type && content_type_name
12018 filename = content_type_name
12019 when content_disposition && content_disp_name
12020 filename = content_disp_name
12021 when content_location && content_loc_name
12022 filename = content_loc_name
12023 else
12024 filename = nil
12025 end
12026 filename
12027 end
12028 def do_delivery
12029 begin
12030 if perform_deliveries
12031 delivery_method.deliver!(self)
12032 end
12033 raise e if raise_delivery_errors
12034 end
12035 end
12036 def decode_body_as_text
12037 body_text = decode_body
12038 if charset
12039 if RUBY_VERSION '1.9'
12040 require 'iconv'
12041 else
12042 if encoding = Encoding.find(charset) rescue nil
12043 body_text.force_encoding(encoding)
12044 end
12045 end
12046 end
12047 body_text
12048 end
12049 end
12050 end
12051 module Mail #:nodoc:
12052 module Multibyte #:nodoc:
12053 class Chars
12054 attr_reader :wrapped_string
12055 alias to_s wrapped_string
12056 alias to_str wrapped_string
12057 if RUBY_VERSION = "1.9"
12058 def initialize(string)
12059 @wrapped_string = string
12060 end
12061 else
12062 def initialize(string) #:nodoc:
12063 @wrapped_string = string
12064 end
12065 end
12066 def method_missing(method, *args, &block)
12067 if method.to_s =~ /!$/
12068 @wrapped_string.__send__(method, *args, &block)
12069 self
12070 else
12071 result.kind_of?(String) ? chars(result) : result
12072 end
12073 end
12074 def respond_to?(method, include_private=false)
12075 end
12076 def acts_like_string?
12077 true
12078 end
12079 def self.consumes?(string)
12080 string.unpack('U*')
12081 true
12082 rescue ArgumentError
12083 false
12084 end
12085 include Comparable
12086 def =(other)
12087 @wrapped_string = other.to_s
12088 end
12089 if RUBY_VERSION "1.9"
12090 def self.wants?(string)
12091 $KCODE == 'UTF8' && consumes?(string)
12092 end
12093 def +(other)
12094 chars(@wrapped_string + other)
12095 end
12096 def =~(other)
12097 translate_offset(@wrapped_string =~ other)
12098 end
12099 def insert(offset, fragment)
12100 unpacked = Unicode.u_unpack(@wrapped_string)
12101 unless offset unpacked.length
12102 @wrapped_string.replace(
12103 )
12104 else
12105 raise IndexError, "index #{offset} out of string"
12106 end
12107 self
12108 end
12109 def include?(other)
12110 @wrapped_string.include?(other)
12111 end
12112 def index(needle, offset=0)
12113 end
12114 def rindex(needle, offset=nil)
12115 offset ||= length
12116 end
12117 def size
12118 Unicode.u_unpack(@wrapped_string).size
12119 end
12120 alias_method :length, :size
12121 def rstrip
12122 end
12123 def lstrip
12124 end
12125 def strip
12126 rstrip.lstrip
12127 end
12128 def ord
12129 Unicode.u_unpack(@wrapped_string)[0]
12130 end
12131 def rjust(integer, padstr=' ')
12132 justify(integer, :right, padstr)
12133 end
12134 def ljust(integer, padstr=' ')
12135 justify(integer, :left, padstr)
12136 end
12137 def center(integer, padstr=' ')
12138 justify(integer, :center, padstr)
12139 end
12140 else
12141 def =~(other)
12142 @wrapped_string =~ other
12143 end
12144 end
12145 def split(*args)
12146 end
12147 def []=(*args)
12148 replace_by = args.pop
12149 if args.first.is_a?(Regexp)
12150 @wrapped_string[*args] = replace_by
12151 else
12152 result = Unicode.u_unpack(@wrapped_string)
12153 if args[0].is_a?(Fixnum)
12154 min = args[0]
12155 max = args[1].nil? ? min : (min + args[1] - 1)
12156 range = Range.new(min, max)
12157 elsif args.first.is_a?(Range)
12158 range = args[0]
12159 else
12160 needle = args[0].to_s
12161 min = index(needle)
12162 max = min + Unicode.u_unpack(needle).length - 1
12163 range = Range.new(min, max)
12164 end
12165 result[range] = Unicode.u_unpack(replace_by)
12166 @wrapped_string.replace(result.pack('U*'))
12167 end
12168 end
12169 def reverse
12170 end
12171 def slice(*args)
12172 if args.size 2
12173 elsif (args.size == 2 && !args[1].is_a?(Numeric))
12174 elsif args[0].kind_of? Range
12175 result = cps.nil? ? nil : cps.pack('U*')
12176 elsif args[0].kind_of? Regexp
12177 result = @wrapped_string.slice(*args)
12178 elsif args.size == 1 && args[0].kind_of?(Numeric)
12179 result = character && [character].pack('U')
12180 else
12181 result = cps && cps.pack('U*')
12182 end
12183 result && chars(result)
12184 end
12185 alias_method :[], :slice
12186 def limit(limit)
12187 slice(0...translate_offset(limit))
12188 end
12189 def upcase
12190 end
12191 def downcase
12192 end
12193 def capitalize
12194 end
12195 def titleize
12196 end
12197 alias_method :titlecase, :titleize
12198 def normalize(form = nil)
12199 chars(Unicode.normalize(@wrapped_string, form))
12200 end
12201 def decompose
12202 end
12203 def compose
12204 end
12205 def g_length
12206 Unicode.g_unpack(@wrapped_string).length
12207 end
12208 def tidy_bytes(force = false)
12209 chars(Unicode.tidy_bytes(@wrapped_string, force))
12210 end
12211 if public_method_defined?(method)
12212 define_method("#{method}!") do |*args|
12213 self
12214 end
12215 end
12216 end
12217 protected
12218 def translate_offset(byte_offset) #:nodoc:
12219 return nil if byte_offset.nil?
12220 return 0 if @wrapped_string == ''
12221 if @wrapped_string.respond_to?(:force_encoding)
12222 end
12223 begin
12224 rescue ArgumentError
12225 byte_offset -= 1
12226 retry
12227 end
12228 end
12229 def justify(integer, way, padstr=' ') #:nodoc:
12230 padsize = integer - size
12231 padsize = padsize 0 ? padsize : 0
12232 case way
12233 when :right
12234 when :left
12235 when :center
12236 lpad = padding((padsize / 2.0).floor, padstr)
12237 rpad = padding((padsize / 2.0).ceil, padstr)
12238 end
12239 chars(result)
12240 end
12241 def padding(padsize, padstr=' ') #:nodoc:
12242 if padsize != 0
12243 else
12244 ''
12245 end
12246 end
12247 def chars(string) #:nodoc:
12248 self.class.new(string)
12249 end
12250 end
12251 end
12252 end
12253 module Mail #:nodoc:
12254 module Multibyte #:nodoc:
12255 class EncodingError StandardError; end
12256 end
12257 endmodule Mail
12258 module Multibyte
12259 module Unicode
12260 extend self
12261 NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
12262 UNICODE_VERSION = '5.2.0'
12263 attr_accessor :default_normalization_form
12264 @default_normalization_form = :kc
12265 HANGUL_SBASE = 0xAC00
12266 HANGUL_LBASE = 0x1100
12267 HANGUL_VBASE = 0x1161
12268 HANGUL_TBASE = 0x11A7
12269 HANGUL_LCOUNT = 19
12270 HANGUL_VCOUNT = 21
12271 HANGUL_TCOUNT = 28
12272 HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT
12273 HANGUL_SCOUNT = 11172
12274 HANGUL_SLAST = HANGUL_SBASE + HANGUL_SCOUNT
12275 HANGUL_JAMO_FIRST = 0x1100
12276 HANGUL_JAMO_LAST = 0x11FF
12277 WHITESPACE = [
12278 0x0020, # White_Space # Zs SPACE
12279 0x0085, # White_Space # Cc control-0085
12280 0x00A0, # White_Space # Zs NO-BREAK SPACE
12281 0x1680, # White_Space # Zs OGHAM SPACE MARK
12282 0x2028, # White_Space # Zl LINE SEPARATOR
12283 0x2029, # White_Space # Zp PARAGRAPH SEPARATOR
12284 0x202F, # White_Space # Zs NARROW NO-BREAK SPACE
12285 0x3000, # White_Space # Zs IDEOGRAPHIC SPACE
12286 ].flatten.freeze
12287 end
12288 def u_unpack(string)
12289 begin
12290 string.unpack 'U*'
12291 rescue ArgumentError
12292 raise EncodingError, 'malformed UTF-8 character'
12293 end
12294 end
12295 def in_char_class?(codepoint, classes)
12296 end
12297 def g_unpack(string)
12298 codepoints = u_unpack(string)
12299 unpacked = []
12300 pos = 0
12301 marker = 0
12302 eoc = codepoints.length
12303 while(pos eoc)
12304 pos += 1
12305 previous = codepoints[pos-1]
12306 current = codepoints[pos]
12307 if (
12308 (database.boundary[:extend] === current)
12309 )
12310 else
12311 unpacked codepoints[marker..pos-1]
12312 marker = pos
12313 end
12314 end
12315 unpacked
12316 end
12317 def g_pack(unpacked)
12318 (unpacked.flatten).pack('U*')
12319 end
12320 def reorder_characters(codepoints)
12321 length = codepoints.length- 1
12322 pos = 0
12323 while pos length do
12324 codepoints[pos..pos+1] = cp2.code, cp1.code
12325 pos += (pos 0 ? -1 : 1)
12326 else
12327 pos += 1
12328 end
12329 end
12330 codepoints
12331 end
12332 def decompose_codepoints(type, codepoints)
12333 codepoints.inject([]) do |decomposed, cp|
12334 if HANGUL_SBASE = cp and cp HANGUL_SLAST
12335 sindex = cp - HANGUL_SBASE
12336 ncp = [] # new codepoints
12337 ncp HANGUL_LBASE + sindex / HANGUL_NCOUNT
12338 tindex = sindex % HANGUL_TCOUNT
12339 ncp (HANGUL_TBASE + tindex) unless tindex == 0
12340 decomposed.concat ncp
12341 else
12342 decomposed cp
12343 end
12344 end
12345 end
12346 def compose_codepoints(codepoints)
12347 pos = 0
12348 eoa = codepoints.length - 1
12349 starter_pos = 0
12350 starter_char = codepoints[0]
12351 previous_combining_class = -1
12352 while pos eoa
12353 pos += 1
12354 lindex = starter_char - HANGUL_LBASE
12355 if 0 = lindex and lindex HANGUL_LCOUNT
12356 if 0 = vindex and vindex HANGUL_VCOUNT
12357 if 0 = tindex and tindex HANGUL_TCOUNT
12358 j = starter_pos + 2
12359 eoa -= 2
12360 else
12361 tindex = 0
12362 j = starter_pos + 1
12363 eoa -= 1
12364 end

Связаться
Выделить
Выделите фрагменты страницы, относящиеся к вашему сообщению
Скрыть сведения
Скрыть всю личную информацию
Отмена