bioinform 0.1.17 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -3
  3. data/LICENSE +0 -1
  4. data/README.md +1 -1
  5. data/TODO.txt +23 -30
  6. data/bin/convert_motif +4 -0
  7. data/bin/pcm2pwm +1 -1
  8. data/bin/split_motifs +1 -1
  9. data/bioinform.gemspec +0 -2
  10. data/lib/bioinform.rb +54 -16
  11. data/lib/bioinform/alphabet.rb +85 -0
  12. data/lib/bioinform/background.rb +90 -0
  13. data/lib/bioinform/cli.rb +1 -2
  14. data/lib/bioinform/cli/convert_motif.rb +52 -17
  15. data/lib/bioinform/cli/pcm2pwm.rb +32 -26
  16. data/lib/bioinform/cli/split_motifs.rb +31 -30
  17. data/lib/bioinform/conversion_algorithms.rb +6 -0
  18. data/lib/bioinform/conversion_algorithms/pcm2ppm_converter.rb +13 -11
  19. data/lib/bioinform/conversion_algorithms/pcm2pwm_converter.rb +39 -11
  20. data/lib/bioinform/conversion_algorithms/pcm2pwm_mara_converter.rb +26 -0
  21. data/lib/bioinform/conversion_algorithms/ppm2pcm_converter.rb +30 -0
  22. data/lib/bioinform/conversion_algorithms/pwm2iupac_pwm_converter.rb +23 -0
  23. data/lib/bioinform/conversion_algorithms/pwm2pcm_converter.rb +85 -0
  24. data/lib/bioinform/data_models.rb +1 -7
  25. data/lib/bioinform/data_models/named_model.rb +38 -0
  26. data/lib/bioinform/data_models/pcm.rb +18 -28
  27. data/lib/bioinform/data_models/pm.rb +73 -170
  28. data/lib/bioinform/data_models/ppm.rb +11 -24
  29. data/lib/bioinform/data_models/pwm.rb +30 -56
  30. data/lib/bioinform/errors.rb +17 -0
  31. data/lib/bioinform/formatters.rb +4 -2
  32. data/lib/bioinform/formatters/consensus_formatter.rb +35 -0
  33. data/lib/bioinform/formatters/motif_formatter.rb +69 -0
  34. data/lib/bioinform/formatters/pretty_matrix_formatter.rb +36 -0
  35. data/lib/bioinform/formatters/transfac_formatter.rb +29 -37
  36. data/lib/bioinform/parsers.rb +1 -8
  37. data/lib/bioinform/parsers/matrix_parser.rb +44 -36
  38. data/lib/bioinform/parsers/motif_splitter.rb +45 -0
  39. data/lib/bioinform/support.rb +46 -14
  40. data/lib/bioinform/support/strip_doc.rb +1 -1
  41. data/lib/bioinform/version.rb +1 -1
  42. data/spec/alphabet_spec.rb +79 -0
  43. data/spec/background_spec.rb +57 -0
  44. data/spec/cli/cli_spec.rb +6 -6
  45. data/spec/cli/convert_motif_spec.rb +88 -88
  46. data/spec/cli/data/pcm2pwm/KLF4_f2.pwm.result +9 -9
  47. data/spec/cli/data/pcm2pwm/SP1_f1.pwm.result +11 -11
  48. data/spec/cli/pcm2pwm_spec.rb +22 -23
  49. data/spec/cli/shared_examples/convert_motif/motif_list_empty.rb +1 -1
  50. data/spec/cli/shared_examples/convert_motif/several_motifs_specified.rb +1 -1
  51. data/spec/cli/shared_examples/convert_motif/single_motif_specified.rb +5 -5
  52. data/spec/cli/shared_examples/convert_motif/yield_help_string.rb +2 -2
  53. data/spec/cli/shared_examples/convert_motif/yield_motif_conversion_error.rb +3 -3
  54. data/spec/cli/split_motifs_spec.rb +6 -21
  55. data/spec/converters/pcm2ppm_converter_spec.rb +32 -0
  56. data/spec/converters/pcm2pwm_converter_spec.rb +71 -0
  57. data/spec/converters/ppm2pcm_converter_spec.rb +32 -0
  58. data/spec/converters/pwm2iupac_pwm_converter_spec.rb +65 -0
  59. data/spec/converters/pwm2pcm_converter_spec.rb +57 -0
  60. data/spec/data_models/named_model_spec.rb +41 -0
  61. data/spec/data_models/pcm_spec.rb +114 -45
  62. data/spec/data_models/pm_spec.rb +132 -333
  63. data/spec/data_models/ppm_spec.rb +47 -44
  64. data/spec/data_models/pwm_spec.rb +85 -77
  65. data/spec/fabricators/motif_formats_fabricator.rb +116 -116
  66. data/spec/formatters/consensus_formatter_spec.rb +26 -0
  67. data/spec/formatters/raw_formatter_spec.rb +169 -0
  68. data/spec/parsers/matrix_parser_spec.rb +216 -0
  69. data/spec/parsers/motif_splitter_spec.rb +87 -0
  70. data/spec/spec_helper.rb +2 -2
  71. data/spec/spec_helper_source.rb +25 -5
  72. data/spec/support_spec.rb +31 -0
  73. metadata +43 -124
  74. data/bin/merge_into_collection +0 -4
  75. data/lib/bioinform/cli/merge_into_collection.rb +0 -80
  76. data/lib/bioinform/conversion_algorithms/ppm2pwm_converter.rb +0 -0
  77. data/lib/bioinform/data_models/collection.rb +0 -75
  78. data/lib/bioinform/data_models/motif.rb +0 -56
  79. data/lib/bioinform/formatters/raw_formatter.rb +0 -41
  80. data/lib/bioinform/parsers/jaspar_parser.rb +0 -35
  81. data/lib/bioinform/parsers/parser.rb +0 -92
  82. data/lib/bioinform/parsers/splittable_parser.rb +0 -57
  83. data/lib/bioinform/parsers/string_fantom_parser.rb +0 -35
  84. data/lib/bioinform/parsers/string_parser.rb +0 -72
  85. data/lib/bioinform/parsers/trivial_parser.rb +0 -34
  86. data/lib/bioinform/parsers/yaml_parser.rb +0 -35
  87. data/lib/bioinform/support/advanced_scan.rb +0 -8
  88. data/lib/bioinform/support/array_product.rb +0 -6
  89. data/lib/bioinform/support/array_zip.rb +0 -6
  90. data/lib/bioinform/support/collect_hash.rb +0 -7
  91. data/lib/bioinform/support/deep_dup.rb +0 -5
  92. data/lib/bioinform/support/delete_many.rb +0 -14
  93. data/lib/bioinform/support/inverf.rb +0 -13
  94. data/lib/bioinform/support/multiline_squish.rb +0 -6
  95. data/lib/bioinform/support/parameters.rb +0 -28
  96. data/lib/bioinform/support/partial_sums.rb +0 -16
  97. data/lib/bioinform/support/same_by.rb +0 -12
  98. data/lib/bioinform/support/third_part/active_support/core_ext/array/extract_options.rb +0 -29
  99. data/lib/bioinform/support/third_part/active_support/core_ext/hash/indifferent_access.rb +0 -23
  100. data/lib/bioinform/support/third_part/active_support/core_ext/hash/keys.rb +0 -54
  101. data/lib/bioinform/support/third_part/active_support/core_ext/module/attribute_accessors.rb +0 -64
  102. data/lib/bioinform/support/third_part/active_support/core_ext/object/try.rb +0 -57
  103. data/lib/bioinform/support/third_part/active_support/core_ext/string/access.rb +0 -99
  104. data/lib/bioinform/support/third_part/active_support/core_ext/string/behavior.rb +0 -6
  105. data/lib/bioinform/support/third_part/active_support/core_ext/string/filters.rb +0 -49
  106. data/lib/bioinform/support/third_part/active_support/core_ext/string/multibyte.rb +0 -72
  107. data/lib/bioinform/support/third_part/active_support/hash_with_indifferent_access.rb +0 -181
  108. data/lib/bioinform/support/third_part/active_support/multibyte.rb +0 -44
  109. data/lib/bioinform/support/third_part/active_support/multibyte/chars.rb +0 -476
  110. data/lib/bioinform/support/third_part/active_support/multibyte/exceptions.rb +0 -8
  111. data/lib/bioinform/support/third_part/active_support/multibyte/unicode.rb +0 -393
  112. data/lib/bioinform/support/third_part/active_support/multibyte/utils.rb +0 -60
  113. data/spec/cli/data/merge_into_collection/GABPA_f1.pwm +0 -14
  114. data/spec/cli/data/merge_into_collection/KLF4_f2.pwm +0 -11
  115. data/spec/cli/data/merge_into_collection/SP1_f1.pwm +0 -12
  116. data/spec/cli/data/merge_into_collection/collection.txt.result +0 -40
  117. data/spec/cli/data/merge_into_collection/collection.yaml.result +0 -188
  118. data/spec/cli/data/merge_into_collection/collection_pwm.yaml.result +0 -188
  119. data/spec/cli/data/merge_into_collection/pwm_folder/GABPA_f1.pwm +0 -14
  120. data/spec/cli/data/merge_into_collection/pwm_folder/KLF4_f2.pwm +0 -11
  121. data/spec/cli/data/merge_into_collection/pwm_folder/SP1_f1.pwm +0 -12
  122. data/spec/cli/data/split_motifs/collection.yaml +0 -188
  123. data/spec/cli/merge_into_collection_spec.rb +0 -100
  124. data/spec/data_models/collection_spec.rb +0 -98
  125. data/spec/data_models/motif_spec.rb +0 -224
  126. data/spec/fabricators/collection_fabricator.rb +0 -8
  127. data/spec/fabricators/motif_fabricator.rb +0 -33
  128. data/spec/fabricators/pcm_fabricator.rb +0 -25
  129. data/spec/fabricators/pm_fabricator.rb +0 -52
  130. data/spec/fabricators/ppm_fabricator.rb +0 -14
  131. data/spec/fabricators/pwm_fabricator.rb +0 -16
  132. data/spec/parsers/parser_spec.rb +0 -152
  133. data/spec/parsers/string_fantom_parser_spec.rb +0 -70
  134. data/spec/parsers/string_parser_spec.rb +0 -77
  135. data/spec/parsers/trivial_parser_spec.rb +0 -64
  136. data/spec/parsers/yaml_parser_spec.rb +0 -50
  137. data/spec/support/advanced_scan_spec.rb +0 -32
  138. data/spec/support/array_product_spec.rb +0 -15
  139. data/spec/support/array_zip_spec.rb +0 -15
  140. data/spec/support/collect_hash_spec.rb +0 -15
  141. data/spec/support/delete_many_spec.rb +0 -44
  142. data/spec/support/inverf_spec.rb +0 -19
  143. data/spec/support/multiline_squish_spec.rb +0 -25
  144. data/spec/support/partial_sums_spec.rb +0 -30
  145. data/spec/support/same_by_spec.rb +0 -36
@@ -1,34 +0,0 @@
1
- require_relative '../support'
2
- require_relative '../parsers/parser'
3
- require_relative '../data_models/collection'
4
- require 'yaml'
5
-
6
- module Bioinform
7
- # TrivialParser can be used to parse hashes returned by #parse method of other parsers:
8
- # PM.new({matrix:[[1,2,3,4],[5,6,7,8]], name: 'Name'}, TrivialParser)
9
- # PM.new(StringParser.new("1 2 3 4\n5 6 7 8").parse)
10
- # StringParser.new("First\n1 2 3 4\n5 6 7 8\nSecond\n0 0 0 0").map{|inp| PM.new(inp, TrivialParser)}
11
- class TrivialParser < Parser
12
- def initialize(input)
13
- @input = input
14
- end
15
- def parse!
16
- case input
17
- when PM then input
18
- when Motif then input.pm
19
- when OpenStruct then input
20
- when Hash then OpenStruct.new(input)
21
- end
22
- end
23
- end
24
-
25
- class TrivialCollectionParser < Parser
26
- include MultipleMotifsParser
27
- def initialize(input)
28
- @input = input
29
- end
30
- def parse!
31
- input.container.shift.pm
32
- end
33
- end
34
- end
@@ -1,35 +0,0 @@
1
- require_relative '../support'
2
- require_relative 'parser'
3
- require_relative '../data_models/collection'
4
- require 'yaml'
5
-
6
- module Bioinform
7
- # YAMLParser can be used to parse hashes returned by #parse method of other parsers:
8
- # yaml_dump_of_pm = PM.new(...).to_yaml
9
- # PM.new(yaml_dump_of_pm, YAMLParser)
10
- class YAMLParser < Parser
11
- def initialize(input)
12
- @input = input
13
- end
14
- def parse!
15
- YAML.load(input)
16
- rescue Psych::SyntaxError
17
- raise 'parsing error'
18
- end
19
- end
20
-
21
- class YAMLCollectionParser < Parser
22
- include MultipleMotifsParser
23
- def initialize(input)
24
- @input = input
25
- end
26
- def collection
27
- @collection ||= YAML.load(input)
28
- end
29
- def parse!
30
- collection.container.shift.pm
31
- rescue Psych::SyntaxError
32
- raise 'parsing error'
33
- end
34
- end
35
- end
@@ -1,8 +0,0 @@
1
- require 'strscan'
2
-
3
- class StringScanner
4
- def advanced_scan(pat)
5
- result = scan(pat)
6
- result && result.match(pat)
7
- end
8
- end
@@ -1,6 +0,0 @@
1
- class Array
2
- def self.product(*arrays)
3
- return [] if arrays.empty?
4
- arrays.first.product(*arrays[1..-1])
5
- end
6
- end
@@ -1,6 +0,0 @@
1
- class Array
2
- def self.zip(*arrays)
3
- return [] if arrays.empty?
4
- arrays.first.zip(*arrays[1..-1])
5
- end
6
- end
@@ -1,7 +0,0 @@
1
- module Enumerable
2
- # %w{A C G T}.collect_hash{|k| [k*2, k*3] }
3
- # # ==> {"AA" => "AAA", "CC" => "CCC", "GG" => "GGG", "TT" => "TTT"}
4
- def collect_hash(&block)
5
- block_given? ? Hash[ collect(&block) ] : Hash[ collect{|k,v| [k,v]} ]
6
- end
7
- end
@@ -1,5 +0,0 @@
1
- class Object
2
- def deep_dup
3
- Marshal.load(Marshal.dump(self))
4
- end
5
- end
@@ -1,14 +0,0 @@
1
- class Array
2
- def delete_at_many(*indices)
3
- indices.uniq.sort.reverse.each{|ind| delete_at ind}
4
- end
5
- def delete_many(*elements)
6
- elements.each{|el| delete el}
7
- end
8
- end
9
-
10
- class Hash
11
- def delete_many(*keys)
12
- keys.each{|el| delete el}
13
- end
14
- end
@@ -1,13 +0,0 @@
1
- module Math
2
- def self.inverf(x)
3
- sign = x < 0 ? -1 : 1
4
- x = x.abs
5
- a = 8 / (3*Math::PI) * (Math::PI-3) / (4-Math::PI)
6
- part0 = ( 2/(Math::PI*a) + (Math.log(1-x*x)) / 2 )**2
7
- part = -2 / (Math::PI * a) - Math.log(1-x*x)/2 + Math.sqrt(-1/a * Math.log(1-x*x) + part0)
8
- sign * Math.sqrt(part)
9
- end
10
- def inverf(x)
11
- Math.inverf(x)
12
- end
13
- end
@@ -1,6 +0,0 @@
1
- require_relative 'third_part/active_support/core_ext/string/filters'
2
- class String
3
- def multiline_squish
4
- split("\n").map(&:squish).join("\n").gsub(/\A\n+/,'').gsub(/\n+\z/,'')
5
- end
6
- end
@@ -1,28 +0,0 @@
1
- require 'ostruct'
2
- module Bioinform
3
- module Parameters
4
- def self.included(base)
5
- base.extend(ClassMethods)
6
- end
7
- module ClassMethods
8
- def make_parameters(*params)
9
- params.each do |param|
10
- define_method(param){ parameters.send(param) }
11
- define_method("#{param}="){|new_value| parameters.send("#{param}=", new_value) }
12
- end
13
- end
14
- end
15
- def parameters; @parameters ||= OpenStruct.new; end
16
- def set_parameters(hsh)
17
- hsh.each{|k,v| send("#{k}=", v) }
18
- self
19
- end
20
- # return hash of parameters
21
- def get_parameters
22
- @parameters.marshal_dump
23
- end
24
- def parameter_defined?(param_name)
25
- get_parameters.has_key?(param_name)
26
- end
27
- end
28
- end
@@ -1,16 +0,0 @@
1
- require_relative 'collect_hash'
2
-
3
- class Array
4
- def partial_sums(initial = 0.0)
5
- sums = initial
6
- map{|el| sums += el}
7
- end
8
- end
9
-
10
- class Hash
11
- # {1 => 5, 4 => 3, 3 => 2}.partial_sums == {1=>5, 3=>7, 4=>10}
12
- def partial_sums(initial = 0.0)
13
- sums = initial
14
- sort.collect_hash{|k,v| [k, sums += v]}
15
- end
16
- end
@@ -1,12 +0,0 @@
1
- module Enumerable
2
- def same_by?(&block)
3
- return true if empty?
4
- if block_given?
5
- first_result = yield(first)
6
- all?{|el| first_result == yield(el)}
7
- else
8
- first_result = first
9
- all?{|el| first_result == el}
10
- end
11
- end
12
- end
@@ -1,29 +0,0 @@
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
@@ -1,23 +0,0 @@
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
@@ -1,54 +0,0 @@
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
@@ -1,64 +0,0 @@
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
@@ -1,57 +0,0 @@
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