1
0

utils.rb 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. require 'jsonpath'
  2. require 'cgi'
  3. module Utils
  4. def self.unindent(s)
  5. s = s.gsub(/\t/, ' ').chomp
  6. min = ((s.split("\n").find {|l| l !~ /^\s*$/ })[/^\s+/, 0] || "").length
  7. if min > 0
  8. s.gsub(/^#{" " * min}/, "")
  9. else
  10. s
  11. end
  12. end
  13. def self.pretty_print(struct, indent = true)
  14. output = JSON.pretty_generate(struct)
  15. if indent
  16. output.gsub(/\n/i, "\n ").tap { |a| p a }
  17. else
  18. output
  19. end
  20. end
  21. def self.interpolate_jsonpaths(value, data, options = {})
  22. if options[:leading_dollarsign_is_jsonpath] && value[0] == '$'
  23. Utils.values_at(data, value).first.to_s
  24. else
  25. value.gsub(/<[^>]+>/).each { |jsonpath|
  26. Utils.values_at(data, jsonpath[1..-2]).first.to_s
  27. }
  28. end
  29. end
  30. def self.recursively_interpolate_jsonpaths(struct, data, options = {})
  31. case struct
  32. when Hash
  33. struct.inject({}) {|memo, (key, value)| memo[key] = recursively_interpolate_jsonpaths(value, data, options); memo }
  34. when Array
  35. struct.map {|elem| recursively_interpolate_jsonpaths(elem, data, options) }
  36. when String
  37. interpolate_jsonpaths(struct, data, options)
  38. else
  39. struct
  40. end
  41. end
  42. def self.value_at(data, path)
  43. values_at(data, path).first
  44. end
  45. def self.values_at(data, path)
  46. if path =~ /\Aescape /
  47. path.gsub!(/\Aescape /, '')
  48. escape = true
  49. else
  50. escape = false
  51. end
  52. result = JsonPath.new(path, :allow_eval => ENV['ALLOW_JSONPATH_EVAL'] == "true").on(data.is_a?(String) ? data : data.to_json)
  53. if escape
  54. result.map {|r| CGI::escape r }
  55. else
  56. result
  57. end
  58. end
  59. # Output JSON that is ready for inclusion into HTML. If you simply use to_json on an object, the
  60. # presence of </script> in the valid JSON can break the page and allow XSS attacks.
  61. # Optionally, pass `:skip_safe => true` to not call html_safe on the output.
  62. def self.jsonify(thing, options = {})
  63. json = thing.to_json.gsub('</', '<\/')
  64. if !options[:skip_safe]
  65. json.html_safe
  66. else
  67. json
  68. end
  69. end
  70. def self.pretty_jsonify(thing)
  71. JSON.pretty_generate(thing).gsub('</', '<\/')
  72. end
  73. class TupleSorter
  74. class SortableTuple
  75. attr_reader :array
  76. # The <=> method will call orders[n] to determine if the nth element
  77. # should be compared in descending order.
  78. def initialize(array, orders = [])
  79. @array = array
  80. @orders = orders
  81. end
  82. def <=> other
  83. other = other.array
  84. @array.each_with_index do |e, i|
  85. o = other[i]
  86. case cmp = e <=> o || e.to_s <=> o.to_s
  87. when 0
  88. next
  89. else
  90. return @orders[i] ? -cmp : cmp
  91. end
  92. end
  93. 0
  94. end
  95. end
  96. class << self
  97. def sort!(array, orders = [])
  98. array.sort_by! do |e|
  99. SortableTuple.new(e, orders)
  100. end
  101. end
  102. end
  103. end
  104. def self.sort_tuples!(array, orders = [])
  105. TupleSorter.sort!(array, orders)
  106. end
  107. end