| 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 | |
| 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 |
Комментарии