1# frozen_string_literal: false 2module RSS 3 4 ## 5 # RSS::Utils is a module that holds various utility functions that are used 6 # across many parts of the rest of the RSS library. Like most modules named 7 # some variant of 'util', its methods are probably not particularly useful 8 # to those who aren't developing the library itself. 9 module Utils 10 module_function 11 12 # Given a +name+ in a name_with_underscores or a name-with-dashes format, 13 # returns the CamelCase version of +name+. 14 # 15 # If the +name+ is already CamelCased, nothing happens. 16 # 17 # Examples: 18 # 19 # require 'rss/utils' 20 # 21 # RSS::Utils.to_class_name("sample_name") 22 # # => "SampleName" 23 # RSS::Utils.to_class_name("with-dashes") 24 # # => "WithDashes" 25 # RSS::Utils.to_class_name("CamelCase") 26 # # => "CamelCase" 27 def to_class_name(name) 28 name.split(/[_\-]/).collect do |part| 29 "#{part[0, 1].upcase}#{part[1..-1]}" 30 end.join("") 31 end 32 33 # Returns an array of two elements: the filename where the calling method 34 # is located, and the line number where it is defined. 35 # 36 # Takes an optional argument +i+, which specifies how many callers up the 37 # stack to look. 38 # 39 # Examples: 40 # 41 # require 'rss/utils' 42 # 43 # def foo 44 # p RSS::Utils.get_file_and_line_from_caller 45 # p RSS::Utils.get_file_and_line_from_caller(1) 46 # end 47 # 48 # def bar 49 # foo 50 # end 51 # 52 # def baz 53 # bar 54 # end 55 # 56 # baz 57 # # => ["test.rb", 5] 58 # # => ["test.rb", 9] 59 # 60 # If +i+ is not given, or is the default value of 0, it attempts to figure 61 # out the correct value. This is useful when in combination with 62 # instance_eval. For example: 63 # 64 # require 'rss/utils' 65 # 66 # def foo 67 # p RSS::Utils.get_file_and_line_from_caller(1) 68 # end 69 # 70 # def bar 71 # foo 72 # end 73 # 74 # instance_eval <<-RUBY, *RSS::Utils.get_file_and_line_from_caller 75 # def baz 76 # bar 77 # end 78 # RUBY 79 # 80 # baz 81 # 82 # # => ["test.rb", 8] 83 def get_file_and_line_from_caller(i=0) 84 file, line, = caller[i].split(':') 85 line = line.to_i 86 line += 1 if i.zero? 87 [file, line] 88 end 89 90 # Takes a string +s+ with some HTML in it, and escapes '&', '"', '<' and '>', by 91 # replacing them with the appropriate entities. 92 # 93 # This method is also aliased to h, for convenience. 94 # 95 # Examples: 96 # 97 # require 'rss/utils' 98 # 99 # RSS::Utils.html_escape("Dungeons & Dragons") 100 # # => "Dungeons & Dragons" 101 # RSS::Utils.h(">_>") 102 # # => ">_>" 103 def html_escape(s) 104 s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<") 105 end 106 alias h html_escape 107 108 # If +value+ is an instance of class +klass+, return it, else 109 # create a new instance of +klass+ with value +value+. 110 def new_with_value_if_need(klass, value) 111 if value.is_a?(klass) 112 value 113 else 114 klass.new(value) 115 end 116 end 117 118 # This method is used inside of several different objects to determine 119 # if special behavior is needed in the constructor. 120 # 121 # Special behavior is needed if the array passed in as +args+ has 122 # +true+ or +false+ as its value, and if the second element of +args+ 123 # is a hash. 124 def element_initialize_arguments?(args) 125 [true, false].include?(args[0]) and args[1].is_a?(Hash) 126 end 127 128 module ExplicitCleanOther 129 module_function 130 def parse(value) 131 if [true, false, nil].include?(value) 132 value 133 else 134 case value.to_s 135 when /\Aexplicit|yes|true\z/i 136 true 137 when /\Aclean|no|false\z/i 138 false 139 else 140 nil 141 end 142 end 143 end 144 end 145 146 module YesOther 147 module_function 148 def parse(value) 149 if [true, false].include?(value) 150 value 151 else 152 /\Ayes\z/i.match(value.to_s) ? true : false 153 end 154 end 155 end 156 157 module CSV 158 module_function 159 def parse(value, &block) 160 if value.is_a?(String) 161 value = value.strip.split(/\s*,\s*/) 162 value = value.collect(&block) if block_given? 163 value 164 else 165 value 166 end 167 end 168 end 169 170 module InheritedReader 171 def inherited_reader(constant_name) 172 base_class = inherited_base 173 result = base_class.const_get(constant_name) 174 found_base_class = false 175 ancestors.reverse_each do |klass| 176 if found_base_class 177 if klass.const_defined?(constant_name) 178 result = yield(result, klass.const_get(constant_name)) 179 end 180 else 181 found_base_class = klass == base_class 182 end 183 end 184 result 185 end 186 187 def inherited_array_reader(constant_name) 188 inherited_reader(constant_name) do |result, current| 189 current + result 190 end 191 end 192 193 def inherited_hash_reader(constant_name) 194 inherited_reader(constant_name) do |result, current| 195 result.merge(current) 196 end 197 end 198 end 199 end 200end 201