bioinform 0.1.11 → 0.1.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|