Upgrade to 1.46.0
[platform/upstream/nghttp2.git] / third-party / mruby / mrblib / string.rb
1 ##
2 # String
3 #
4 # ISO 15.2.10
5 class String
6   # ISO 15.2.10.3
7   include Comparable
8
9   ##
10   # Calls the given block for each line
11   # and pass the respective line.
12   #
13   # ISO 15.2.10.5.15
14   def each_line(separator = "\n", &block)
15     return to_enum(:each_line, separator) unless block
16
17     if separator.nil?
18       block.call(self)
19       return self
20     end
21     raise TypeError unless separator.is_a?(String)
22
23     paragraph_mode = false
24     if separator.empty?
25       paragraph_mode = true
26       separator = "\n\n"
27     end
28     start = 0
29     string = dup
30     self_len = length
31     sep_len = separator.length
32     should_yield_subclass_instances = self.class != String
33
34     while (pointer = string.index(separator, start))
35       pointer += sep_len
36       pointer += 1 while paragraph_mode && string[pointer] == "\n"
37       if should_yield_subclass_instances
38         block.call(self.class.new(string[start, pointer - start]))
39       else
40         block.call(string[start, pointer - start])
41       end
42       start = pointer
43     end
44     return self if start == self_len
45
46     if should_yield_subclass_instances
47       block.call(self.class.new(string[start, self_len - start]))
48     else
49       block.call(string[start, self_len - start])
50     end
51     self
52   end
53
54   # private method for gsub/sub
55   def __sub_replace(pre, m, post)
56     s = ""
57     i = 0
58     while j = index("\\", i)
59       break if j == length-1
60       t = case self[j+1]
61           when "\\"
62             "\\"
63           when "`"
64             pre
65           when "&", "0"
66             m
67           when "'"
68             post
69           when "1", "2", "3", "4", "5", "6", "7", "8", "9"
70             ""
71           else
72             self[j, 2]
73           end
74       s += self[i, j-i] + t
75       i = j + 2
76     end
77     s + self[i, length-i]
78   end
79
80   ##
81   # Replace all matches of +pattern+ with +replacement+.
82   # Call block (if given) for each match and replace
83   # +pattern+ with the value of the block. Return the
84   # final value.
85   #
86   # ISO 15.2.10.5.18
87   def gsub(*args, &block)
88     return to_enum(:gsub, *args) if args.length == 1 && !block
89     raise ArgumentError, "wrong number of arguments" unless (1..2).include?(args.length)
90
91     pattern, replace = *args
92     plen = pattern.length
93     if args.length == 2 && block
94       block = nil
95     end
96     if !replace.nil? || !block
97       replace.__to_str
98     end
99     offset = 0
100     result = []
101     while found = index(pattern, offset)
102       result << self[offset, found - offset]
103       offset = found + plen
104       result << if block
105         block.call(pattern).to_s
106       else
107         replace.__sub_replace(self[0, found], pattern, self[offset..-1] || "")
108       end
109       if plen == 0
110         result << self[offset, 1]
111         offset += 1
112       end
113     end
114     result << self[offset..-1] if offset < length
115     result.join
116   end
117
118   ##
119   # Replace all matches of +pattern+ with +replacement+.
120   # Call block (if given) for each match and replace
121   # +pattern+ with the value of the block. Modify
122   # +self+ with the final value.
123   #
124   # ISO 15.2.10.5.19
125   def gsub!(*args, &block)
126     raise FrozenError, "can't modify frozen String" if frozen?
127     return to_enum(:gsub!, *args) if args.length == 1 && !block
128     str = self.gsub(*args, &block)
129     return nil unless self.index(args[0])
130     self.replace(str)
131   end
132
133 #  ##
134 #  # Calls the given block for each match of +pattern+
135 #  # If no block is given return an array with all
136 #  # matches of +pattern+.
137 #  #
138 #  # ISO 15.2.10.5.32
139 #  def scan(pattern, &block)
140 #    # TODO: String#scan is not implemented yet
141 #  end
142
143   ##
144   # Replace only the first match of +pattern+ with
145   # +replacement+. Call block (if given) for each
146   # match and replace +pattern+ with the value of the
147   # block. Return the final value.
148   #
149   # ISO 15.2.10.5.36
150   def sub(*args, &block)
151     unless (1..2).include?(args.length)
152       raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 2)"
153     end
154
155     pattern, replace = *args
156     pattern.__to_str
157     if args.length == 2 && block
158       block = nil
159     end
160     unless block
161       replace.__to_str
162     end
163     result = []
164     this = dup
165     found = index(pattern)
166     return this unless found
167     result << this[0, found]
168     offset = found + pattern.length
169     result << if block
170       block.call(pattern).to_s
171     else
172       replace.__sub_replace(this[0, found], pattern, this[offset..-1] || "")
173     end
174     result << this[offset..-1] if offset < length
175     result.join
176   end
177
178   ##
179   # Replace only the first match of +pattern+ with
180   # +replacement+. Call block (if given) for each
181   # match and replace +pattern+ with the value of the
182   # block. Modify +self+ with the final value.
183   #
184   # ISO 15.2.10.5.37
185   def sub!(*args, &block)
186     raise FrozenError, "can't modify frozen String" if frozen?
187     str = self.sub(*args, &block)
188     return nil unless self.index(args[0])
189     self.replace(str)
190   end
191
192   ##
193   # Call the given block for each byte of +self+.
194   def each_byte(&block)
195     return to_enum(:each_byte, &block) unless block
196     bytes = self.bytes
197     pos = 0
198     while pos < bytes.size
199       block.call(bytes[pos])
200       pos += 1
201     end
202     self
203   end
204
205   # those two methods requires Regexp that is optional in mruby
206   ##
207   # ISO 15.2.10.5.3
208   #def =~(re)
209   # re =~ self
210   #end
211
212   ##
213   # ISO 15.2.10.5.27
214   #def match(re, &block)
215   #  re.match(self, &block)
216   #end
217 end