liquid_droppable.rb 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. # frozen_string_literal: true
  2. # Include this mix-in to make a class droppable to Liquid, and adjust
  3. # its behavior in Liquid by implementing its dedicated Drop class
  4. # named with a "Drop" suffix.
  5. module LiquidDroppable
  6. extend ActiveSupport::Concern
  7. class Drop < Liquid::Drop
  8. def initialize(object)
  9. @object = object
  10. end
  11. def to_s
  12. @object.to_s
  13. end
  14. def each
  15. (public_instance_methods - Drop.public_instance_methods).each { |name|
  16. yield [name, __send__(name)]
  17. }
  18. end
  19. def as_json
  20. return {} unless defined?(self.class::METHODS)
  21. Hash[self.class::METHODS.map { |m| [m, send(m).as_json]}]
  22. end
  23. end
  24. included do
  25. const_set :Drop,
  26. if Kernel.const_defined?(drop_name = "#{name}Drop")
  27. Kernel.const_get(drop_name)
  28. else
  29. Kernel.const_set(drop_name, Class.new(Drop))
  30. end
  31. end
  32. def to_liquid
  33. self.class::Drop.new(self)
  34. end
  35. class MatchDataDrop < Drop
  36. METHODS = %w[pre_match post_match names size]
  37. METHODS.each { |attr|
  38. define_method(attr) {
  39. @object.__send__(attr)
  40. }
  41. }
  42. def to_s
  43. @object[0]
  44. end
  45. def liquid_method_missing(method)
  46. @object[method]
  47. rescue IndexError
  48. nil
  49. end
  50. end
  51. class ::MatchData
  52. def to_liquid
  53. MatchDataDrop.new(self)
  54. end
  55. end
  56. require 'uri'
  57. class URIDrop < Drop
  58. METHODS = URI::Generic::COMPONENT
  59. METHODS.each { |attr|
  60. define_method(attr) {
  61. @object.__send__(attr)
  62. }
  63. }
  64. end
  65. class ::URI::Generic
  66. def to_liquid
  67. URIDrop.new(self)
  68. end
  69. end
  70. class ActiveRecordCollectionDrop < Drop
  71. include Enumerable
  72. def each(&block)
  73. @object.each(&block)
  74. end
  75. # required for variable indexing as array
  76. def [](i)
  77. case i
  78. when Integer
  79. @object[i]
  80. when 'size', 'first', 'last'
  81. __send__(i)
  82. end
  83. end
  84. # required for variable indexing as array
  85. def fetch(i, &block)
  86. @object.fetch(i, &block)
  87. end
  88. # compatibility with array; also required by the `size` filter
  89. def size
  90. @object.count
  91. end
  92. # compatibility with array
  93. def first
  94. @object.first
  95. end
  96. # compatibility with array
  97. def last
  98. @object.last
  99. end
  100. # This drop currently does not support the `slice` filter.
  101. end
  102. class ::ActiveRecord::Associations::CollectionProxy
  103. def to_liquid
  104. ActiveRecordCollectionDrop.new(self)
  105. end
  106. end
  107. end