bioinform 0.1.11 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/TODO.txt +2 -0
- data/bioinform.gemspec +0 -6
- data/lib/bioinform/data_models/motif.rb +1 -1
- data/lib/bioinform/data_models/pm.rb +2 -1
- data/lib/bioinform/data_models/pwm.rb +4 -5
- data/lib/bioinform/support/multiline_squish.rb +1 -1
- data/lib/bioinform/support/third_part/active_support/core_ext/array/extract_options.rb +29 -0
- data/lib/bioinform/support/third_part/active_support/core_ext/hash/indifferent_access.rb +23 -0
- data/lib/bioinform/support/third_part/active_support/core_ext/hash/keys.rb +54 -0
- data/lib/bioinform/support/third_part/active_support/core_ext/module/attribute_accessors.rb +64 -0
- data/lib/bioinform/support/third_part/active_support/core_ext/object/try.rb +57 -0
- data/lib/bioinform/support/third_part/active_support/core_ext/string/access.rb +99 -0
- data/lib/bioinform/support/third_part/active_support/core_ext/string/behavior.rb +6 -0
- data/lib/bioinform/support/third_part/active_support/core_ext/string/filters.rb +49 -0
- data/lib/bioinform/support/third_part/active_support/core_ext/string/multibyte.rb +72 -0
- data/lib/bioinform/support/third_part/active_support/hash_with_indifferent_access.rb +178 -0
- data/lib/bioinform/support/third_part/active_support/multibyte/chars.rb +476 -0
- data/lib/bioinform/support/third_part/active_support/multibyte/exceptions.rb +8 -0
- data/lib/bioinform/support/third_part/active_support/multibyte/unicode.rb +393 -0
- data/lib/bioinform/support/third_part/active_support/multibyte/utils.rb +60 -0
- data/lib/bioinform/support/third_part/active_support/multibyte.rb +44 -0
- data/lib/bioinform/support.rb +2 -2
- data/lib/bioinform/version.rb +1 -1
- data/spec/spec_helper.rb +10 -20
- metadata +21 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bce1095da9311ea0d77479899064e74e5979c516
|
4
|
+
data.tar.gz: 3cdd8b774e7ad7cb930965bb5112c9046552f924
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40c7a5191db1b2137de61d5e4b038fca9bb2ec14289ef3010a012a1fd1adb8f47d0b650bcd66b04ecfdac44104754a699ff8cf9b3e004e21834c8aeedddf521c
|
7
|
+
data.tar.gz: 9c2c7ce0367b030b318117f6fc7b597ed9886312e26c64f0bea32157485896f836cb7f30e91777b5f6df1944ac6cc2d53cf1b5c96019a236036fe306d4b86c9c
|
data/Gemfile
CHANGED
data/TODO.txt
CHANGED
data/bioinform.gemspec
CHANGED
@@ -15,11 +15,5 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Bioinform::VERSION
|
17
17
|
|
18
|
-
gem.add_dependency('activesupport', '>= 3.0.0')
|
19
18
|
gem.add_dependency('docopt', '= 0.5.0')
|
20
|
-
|
21
|
-
gem.add_development_dependency('fakefs', '~> 0.4.2')
|
22
|
-
gem.add_development_dependency('fabrication', '~> 2.5.0')
|
23
|
-
gem.add_development_dependency('rspec', '>= 2.0')
|
24
|
-
gem.add_development_dependency('rspec-given', '>= 2.0.0')
|
25
19
|
end
|
@@ -4,7 +4,8 @@ require_relative '../parsers'
|
|
4
4
|
require_relative '../formatters'
|
5
5
|
|
6
6
|
module Bioinform
|
7
|
-
IndexByLetter = {'A' => 0, 'C' => 1, 'G' => 2, 'T' => 3, A: 0, C: 1, G: 2, T: 3
|
7
|
+
IndexByLetter = { 'A' => 0, 'C' => 1, 'G' => 2, 'T' => 3, A: 0, C: 1, G: 2, T: 3,
|
8
|
+
'a' => 0, 'c' => 1, 'g' => 2, 't' => 3, a: 0, c: 1, g: 2, t: 3}
|
8
9
|
LetterByIndex = {0 => :A, 1 => :C, 2 => :G, 3 => :T}
|
9
10
|
|
10
11
|
class PM
|
@@ -19,7 +19,6 @@ module Bioinform
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def score(word)
|
22
|
-
word = word.upcase
|
23
22
|
raise ArgumentError, 'word in PWM#score(word) should have the same length as matrix' unless word.length == length
|
24
23
|
#raise ArgumentError, 'word in PWM#score(word) should have only ACGT-letters' unless word.each_char.all?{|letter| %w{A C G T}.include? letter}
|
25
24
|
(0...length).map do |pos|
|
@@ -27,11 +26,11 @@ module Bioinform
|
|
27
26
|
if IndexByLetter[letter]
|
28
27
|
matrix[pos][IndexByLetter[letter]]
|
29
28
|
elsif letter == 'N'
|
30
|
-
matrix[pos].zip(probability).map{|el, p| el * p}.inject(0
|
29
|
+
matrix[pos].zip(probability).map{|el, p| el * p}.inject(0, &:+)
|
31
30
|
else
|
32
31
|
raise ArgumentError, "word in PWM#score(#{word}) should have only ACGT or N letters"
|
33
32
|
end
|
34
|
-
end.inject(0
|
33
|
+
end.inject(0, &:+).to_f
|
35
34
|
end
|
36
35
|
|
37
36
|
def to_pwm
|
@@ -39,10 +38,10 @@ module Bioinform
|
|
39
38
|
end
|
40
39
|
|
41
40
|
def best_score
|
42
|
-
|
41
|
+
best_suffix(0)
|
43
42
|
end
|
44
43
|
def worst_score
|
45
|
-
|
44
|
+
worst_suffix(0)
|
46
45
|
end
|
47
46
|
|
48
47
|
# best score of suffix s[i..l]
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Hash
|
2
|
+
# By default, only instances of Hash itself are extractable.
|
3
|
+
# Subclasses of Hash may implement this method and return
|
4
|
+
# true to declare themselves as extractable. If a Hash
|
5
|
+
# is extractable, Array#extract_options! pops it from
|
6
|
+
# the Array when it is the last element of the Array.
|
7
|
+
def extractable_options?
|
8
|
+
instance_of?(Hash)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Array
|
13
|
+
# Extracts options from a set of arguments. Removes and returns the last
|
14
|
+
# element in the array if it's a hash, otherwise returns a blank hash.
|
15
|
+
#
|
16
|
+
# def options(*args)
|
17
|
+
# args.extract_options!
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# options(1, 2) # => {}
|
21
|
+
# options(1, 2, :a => :b) # => {:a=>:b}
|
22
|
+
def extract_options!
|
23
|
+
if last.is_a?(Hash) && last.extractable_options?
|
24
|
+
pop
|
25
|
+
else
|
26
|
+
{}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative '../../hash_with_indifferent_access'
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
# Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver:
|
5
|
+
#
|
6
|
+
# {:a => 1}.with_indifferent_access["a"] # => 1
|
7
|
+
#
|
8
|
+
def with_indifferent_access
|
9
|
+
ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Called when object is nested under an object that receives
|
13
|
+
# #with_indifferent_access. This method will be called on the current object
|
14
|
+
# by the enclosing object and is aliased to #with_indifferent_access by
|
15
|
+
# default. Subclasses of Hash may overwrite this method to return +self+ if
|
16
|
+
# converting to an <tt>ActiveSupport::HashWithIndifferentAccess</tt> would not be
|
17
|
+
# desirable.
|
18
|
+
#
|
19
|
+
# b = {:b => 1}
|
20
|
+
# {:a => b}.with_indifferent_access["a"] # calls b.nested_under_indifferent_access
|
21
|
+
#
|
22
|
+
alias nested_under_indifferent_access with_indifferent_access
|
23
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Hash
|
2
|
+
# Return a new hash with all keys converted to strings.
|
3
|
+
#
|
4
|
+
# { :name => 'Rob', :years => '28' }.stringify_keys
|
5
|
+
# #=> { "name" => "Rob", "years" => "28" }
|
6
|
+
def stringify_keys
|
7
|
+
dup.stringify_keys!
|
8
|
+
end
|
9
|
+
|
10
|
+
# Destructively convert all keys to strings. Same as
|
11
|
+
# +stringify_keys+, but modifies +self+.
|
12
|
+
def stringify_keys!
|
13
|
+
keys.each do |key|
|
14
|
+
self[key.to_s] = delete(key)
|
15
|
+
end
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return a new hash with all keys converted to symbols, as long as
|
20
|
+
# they respond to +to_sym+.
|
21
|
+
#
|
22
|
+
# { 'name' => 'Rob', 'years' => '28' }.symbolize_keys
|
23
|
+
# #=> { :name => "Rob", :years => "28" }
|
24
|
+
def symbolize_keys
|
25
|
+
dup.symbolize_keys!
|
26
|
+
end
|
27
|
+
|
28
|
+
# Destructively convert all keys to symbols, as long as they respond
|
29
|
+
# to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
|
30
|
+
def symbolize_keys!
|
31
|
+
keys.each do |key|
|
32
|
+
self[(key.to_sym rescue key) || key] = delete(key)
|
33
|
+
end
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
alias_method :to_options, :symbolize_keys
|
38
|
+
alias_method :to_options!, :symbolize_keys!
|
39
|
+
|
40
|
+
# Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
|
41
|
+
# Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
|
42
|
+
# as keys, this will fail.
|
43
|
+
#
|
44
|
+
# ==== Examples
|
45
|
+
# { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
|
46
|
+
# { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key: name"
|
47
|
+
# { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
|
48
|
+
def assert_valid_keys(*valid_keys)
|
49
|
+
valid_keys.flatten!
|
50
|
+
each_key do |k|
|
51
|
+
raise(ArgumentError, "Unknown key: #{k}") unless valid_keys.include?(k)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative '../array/extract_options'
|
2
|
+
|
3
|
+
class Module
|
4
|
+
def mattr_reader(*syms)
|
5
|
+
options = syms.extract_options!
|
6
|
+
syms.each do |sym|
|
7
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
8
|
+
@@#{sym} = nil unless defined? @@#{sym}
|
9
|
+
|
10
|
+
def self.#{sym}
|
11
|
+
@@#{sym}
|
12
|
+
end
|
13
|
+
EOS
|
14
|
+
|
15
|
+
unless options[:instance_reader] == false || options[:instance_accessor] == false
|
16
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
17
|
+
def #{sym}
|
18
|
+
@@#{sym}
|
19
|
+
end
|
20
|
+
EOS
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def mattr_writer(*syms)
|
26
|
+
options = syms.extract_options!
|
27
|
+
syms.each do |sym|
|
28
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
29
|
+
def self.#{sym}=(obj)
|
30
|
+
@@#{sym} = obj
|
31
|
+
end
|
32
|
+
EOS
|
33
|
+
|
34
|
+
unless options[:instance_writer] == false || options[:instance_accessor] == false
|
35
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
36
|
+
def #{sym}=(obj)
|
37
|
+
@@#{sym} = obj
|
38
|
+
end
|
39
|
+
EOS
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Extends the module object with module and instance accessors for class attributes,
|
45
|
+
# just like the native attr* accessors for instance attributes.
|
46
|
+
#
|
47
|
+
# module AppConfiguration
|
48
|
+
# mattr_accessor :google_api_key
|
49
|
+
# self.google_api_key = "123456789"
|
50
|
+
#
|
51
|
+
# mattr_accessor :paypal_url
|
52
|
+
# self.paypal_url = "www.sandbox.paypal.com"
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# AppConfiguration.google_api_key = "overriding the api key!"
|
56
|
+
#
|
57
|
+
# To opt out of the instance writer method, pass :instance_writer => false.
|
58
|
+
# To opt out of the instance reader method, pass :instance_reader => false.
|
59
|
+
# To opt out of both instance methods, pass :instance_accessor => false.
|
60
|
+
def mattr_accessor(*syms)
|
61
|
+
mattr_reader(*syms)
|
62
|
+
mattr_writer(*syms)
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Object
|
2
|
+
# Invokes the method identified by the symbol +method+, passing it any arguments
|
3
|
+
# and/or the block specified, just like the regular Ruby <tt>Object#send</tt> does.
|
4
|
+
#
|
5
|
+
# *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
|
6
|
+
# and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
|
7
|
+
#
|
8
|
+
# If try is called without a method to call, it will yield any given block with the object.
|
9
|
+
#
|
10
|
+
# Please also note that +try+ is defined on +Object+, therefore it won't work with
|
11
|
+
# subclasses of +BasicObject+. For example, using try with +SimpleDelegator+ will
|
12
|
+
# delegate +try+ to target instead of calling it on delegator itself.
|
13
|
+
#
|
14
|
+
# ==== Examples
|
15
|
+
#
|
16
|
+
# Without +try+
|
17
|
+
# @person && @person.name
|
18
|
+
# or
|
19
|
+
# @person ? @person.name : nil
|
20
|
+
#
|
21
|
+
# With +try+
|
22
|
+
# @person.try(:name)
|
23
|
+
#
|
24
|
+
# +try+ also accepts arguments and/or a block, for the method it is trying
|
25
|
+
# Person.try(:find, 1)
|
26
|
+
# @people.try(:collect) {|p| p.name}
|
27
|
+
#
|
28
|
+
# Without a method argument try will yield to the block unless the receiver is nil.
|
29
|
+
# @person.try { |p| "#{p.first_name} #{p.last_name}" }
|
30
|
+
#--
|
31
|
+
# +try+ behaves like +Object#send+, unless called on +NilClass+.
|
32
|
+
def try(*a, &b)
|
33
|
+
if a.empty? && block_given?
|
34
|
+
yield self
|
35
|
+
else
|
36
|
+
__send__(*a, &b)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class NilClass
|
42
|
+
# Calling +try+ on +nil+ always returns +nil+.
|
43
|
+
# It becomes specially helpful when navigating through associations that may return +nil+.
|
44
|
+
#
|
45
|
+
# === Examples
|
46
|
+
#
|
47
|
+
# nil.try(:name) # => nil
|
48
|
+
#
|
49
|
+
# Without +try+
|
50
|
+
# @person && !@person.children.blank? && @person.children.first.name
|
51
|
+
#
|
52
|
+
# With +try+
|
53
|
+
# @person.try(:children).try(:first).try(:name)
|
54
|
+
def try(*args)
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require_relative "../../multibyte"
|
2
|
+
|
3
|
+
class String
|
4
|
+
unless '1.9'.respond_to?(:force_encoding)
|
5
|
+
# Returns the character at the +position+ treating the string as an array (where 0 is the first character).
|
6
|
+
#
|
7
|
+
# Examples:
|
8
|
+
# "hello".at(0) # => "h"
|
9
|
+
# "hello".at(4) # => "o"
|
10
|
+
# "hello".at(10) # => ERROR if < 1.9, nil in 1.9
|
11
|
+
def at(position)
|
12
|
+
mb_chars[position, 1].to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the remaining of the string from the +position+ treating the string as an array (where 0 is the first character).
|
16
|
+
#
|
17
|
+
# Examples:
|
18
|
+
# "hello".from(0) # => "hello"
|
19
|
+
# "hello".from(2) # => "llo"
|
20
|
+
# "hello".from(10) # => "" if < 1.9, nil in 1.9
|
21
|
+
def from(position)
|
22
|
+
mb_chars[position..-1].to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the beginning of the string up to the +position+ treating the string as an array (where 0 is the first character).
|
26
|
+
#
|
27
|
+
# Examples:
|
28
|
+
# "hello".to(0) # => "h"
|
29
|
+
# "hello".to(2) # => "hel"
|
30
|
+
# "hello".to(10) # => "hello"
|
31
|
+
def to(position)
|
32
|
+
mb_chars[0..position].to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the first character of the string or the first +limit+ characters.
|
36
|
+
#
|
37
|
+
# Examples:
|
38
|
+
# "hello".first # => "h"
|
39
|
+
# "hello".first(2) # => "he"
|
40
|
+
# "hello".first(10) # => "hello"
|
41
|
+
def first(limit = 1)
|
42
|
+
if limit == 0
|
43
|
+
''
|
44
|
+
elsif limit >= size
|
45
|
+
self
|
46
|
+
else
|
47
|
+
mb_chars[0...limit].to_s
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the last character of the string or the last +limit+ characters.
|
52
|
+
#
|
53
|
+
# Examples:
|
54
|
+
# "hello".last # => "o"
|
55
|
+
# "hello".last(2) # => "lo"
|
56
|
+
# "hello".last(10) # => "hello"
|
57
|
+
def last(limit = 1)
|
58
|
+
if limit == 0
|
59
|
+
''
|
60
|
+
elsif limit >= size
|
61
|
+
self
|
62
|
+
else
|
63
|
+
mb_chars[(-limit)..-1].to_s
|
64
|
+
end
|
65
|
+
end
|
66
|
+
else
|
67
|
+
def at(position)
|
68
|
+
self[position]
|
69
|
+
end
|
70
|
+
|
71
|
+
def from(position)
|
72
|
+
self[position..-1]
|
73
|
+
end
|
74
|
+
|
75
|
+
def to(position)
|
76
|
+
self[0..position]
|
77
|
+
end
|
78
|
+
|
79
|
+
def first(limit = 1)
|
80
|
+
if limit == 0
|
81
|
+
''
|
82
|
+
elsif limit >= size
|
83
|
+
self
|
84
|
+
else
|
85
|
+
to(limit - 1)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def last(limit = 1)
|
90
|
+
if limit == 0
|
91
|
+
''
|
92
|
+
elsif limit >= size
|
93
|
+
self
|
94
|
+
else
|
95
|
+
from(-limit)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative 'multibyte'
|
2
|
+
|
3
|
+
class String
|
4
|
+
# Returns the string, first removing all whitespace on both ends of
|
5
|
+
# the string, and then changing remaining consecutive whitespace
|
6
|
+
# groups into one space each.
|
7
|
+
#
|
8
|
+
# Examples:
|
9
|
+
# %{ Multi-line
|
10
|
+
# string }.squish # => "Multi-line string"
|
11
|
+
# " foo bar \n \t boo".squish # => "foo bar boo"
|
12
|
+
def squish
|
13
|
+
dup.squish!
|
14
|
+
end
|
15
|
+
|
16
|
+
# Performs a destructive squish. See String#squish.
|
17
|
+
def squish!
|
18
|
+
strip!
|
19
|
+
gsub!(/\s+/, ' ')
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
|
24
|
+
#
|
25
|
+
# "Once upon a time in a world far far away".truncate(27)
|
26
|
+
# # => "Once upon a time in a wo..."
|
27
|
+
#
|
28
|
+
# Pass a <tt>:separator</tt> to truncate +text+ at a natural break:
|
29
|
+
#
|
30
|
+
# "Once upon a time in a world far far away".truncate(27, :separator => ' ')
|
31
|
+
# # => "Once upon a time in a..."
|
32
|
+
#
|
33
|
+
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
|
34
|
+
# for a total length not exceeding <tt>:length</tt>:
|
35
|
+
#
|
36
|
+
# "And they found that many people were sleeping better.".truncate(25, :omission => "... (continued)")
|
37
|
+
# # => "And they f... (continued)"
|
38
|
+
def truncate(length, options = {})
|
39
|
+
text = self.dup
|
40
|
+
options[:omission] ||= "..."
|
41
|
+
|
42
|
+
length_with_room_for_omission = length - options[:omission].mb_chars.length
|
43
|
+
chars = text.mb_chars
|
44
|
+
stop = options[:separator] ?
|
45
|
+
(chars.rindex(options[:separator].mb_chars, length_with_room_for_omission) || length_with_room_for_omission) : length_with_room_for_omission
|
46
|
+
|
47
|
+
(chars.length > length ? chars[0...stop] + options[:omission] : text).to_s
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative '../../multibyte'
|
3
|
+
|
4
|
+
class String
|
5
|
+
if RUBY_VERSION >= "1.9"
|
6
|
+
# == Multibyte proxy
|
7
|
+
#
|
8
|
+
# +mb_chars+ is a multibyte safe proxy for string methods.
|
9
|
+
#
|
10
|
+
# In Ruby 1.8 and older it creates and returns an instance of the ActiveSupport::Multibyte::Chars class which
|
11
|
+
# encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
|
12
|
+
# class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
|
13
|
+
#
|
14
|
+
# name = 'Claus Müller'
|
15
|
+
# name.reverse # => "rell??M sualC"
|
16
|
+
# name.length # => 13
|
17
|
+
#
|
18
|
+
# name.mb_chars.reverse.to_s # => "rellüM sualC"
|
19
|
+
# name.mb_chars.length # => 12
|
20
|
+
#
|
21
|
+
# In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that
|
22
|
+
# it becomes easy to run one version of your code on multiple Ruby versions.
|
23
|
+
#
|
24
|
+
# == Method chaining
|
25
|
+
#
|
26
|
+
# All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
|
27
|
+
# method chaining on the result of any of these methods.
|
28
|
+
#
|
29
|
+
# name.mb_chars.reverse.length # => 12
|
30
|
+
#
|
31
|
+
# == Interoperability and configuration
|
32
|
+
#
|
33
|
+
# The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
|
34
|
+
# String and Char work like expected. The bang! methods change the internal string representation in the Chars
|
35
|
+
# object. Interoperability problems can be resolved easily with a +to_s+ call.
|
36
|
+
#
|
37
|
+
# For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars. For
|
38
|
+
# information about how to change the default Multibyte behavior see ActiveSupport::Multibyte.
|
39
|
+
def mb_chars
|
40
|
+
if ActiveSupport::Multibyte.proxy_class.consumes?(self)
|
41
|
+
ActiveSupport::Multibyte.proxy_class.new(self)
|
42
|
+
else
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def is_utf8?
|
48
|
+
case encoding
|
49
|
+
when Encoding::UTF_8
|
50
|
+
valid_encoding?
|
51
|
+
when Encoding::ASCII_8BIT, Encoding::US_ASCII
|
52
|
+
dup.force_encoding(Encoding::UTF_8).valid_encoding?
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
def mb_chars
|
59
|
+
if ActiveSupport::Multibyte.proxy_class.wants?(self)
|
60
|
+
ActiveSupport::Multibyte.proxy_class.new(self)
|
61
|
+
else
|
62
|
+
self
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns true if the string has UTF-8 semantics (a String used for purely byte resources is unlikely to have
|
67
|
+
# them), returns false otherwise.
|
68
|
+
def is_utf8?
|
69
|
+
ActiveSupport::Multibyte::Chars.consumes?(self)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|