opal-factory_girl 4.5.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/factory_girl/lib/factory_girl.rb +132 -0
  3. data/factory_girl/lib/factory_girl/aliases.rb +18 -0
  4. data/factory_girl/lib/factory_girl/attribute.rb +62 -0
  5. data/factory_girl/lib/factory_girl/attribute/association.rb +27 -0
  6. data/factory_girl/lib/factory_girl/attribute/dynamic.rb +24 -0
  7. data/factory_girl/lib/factory_girl/attribute/sequence.rb +16 -0
  8. data/factory_girl/lib/factory_girl/attribute/static.rb +16 -0
  9. data/factory_girl/lib/factory_girl/attribute_assigner.rb +97 -0
  10. data/factory_girl/lib/factory_girl/attribute_list.rb +67 -0
  11. data/factory_girl/lib/factory_girl/callback.rb +40 -0
  12. data/factory_girl/lib/factory_girl/callbacks_observer.rb +21 -0
  13. data/factory_girl/lib/factory_girl/configuration.rb +33 -0
  14. data/factory_girl/lib/factory_girl/declaration.rb +23 -0
  15. data/factory_girl/lib/factory_girl/declaration/association.rb +28 -0
  16. data/factory_girl/lib/factory_girl/declaration/dynamic.rb +26 -0
  17. data/factory_girl/lib/factory_girl/declaration/implicit.rb +33 -0
  18. data/factory_girl/lib/factory_girl/declaration/static.rb +26 -0
  19. data/factory_girl/lib/factory_girl/declaration_list.rb +49 -0
  20. data/factory_girl/lib/factory_girl/decorator.rb +21 -0
  21. data/factory_girl/lib/factory_girl/decorator/attribute_hash.rb +17 -0
  22. data/factory_girl/lib/factory_girl/decorator/class_key_hash.rb +27 -0
  23. data/factory_girl/lib/factory_girl/decorator/disallows_duplicates_registry.rb +13 -0
  24. data/factory_girl/lib/factory_girl/decorator/invocation_tracker.rb +19 -0
  25. data/factory_girl/lib/factory_girl/decorator/new_constructor.rb +12 -0
  26. data/factory_girl/lib/factory_girl/definition.rb +141 -0
  27. data/factory_girl/lib/factory_girl/definition_hierarchy.rb +48 -0
  28. data/factory_girl/lib/factory_girl/definition_proxy.rb +174 -0
  29. data/factory_girl/lib/factory_girl/errors.rb +25 -0
  30. data/factory_girl/lib/factory_girl/evaluation.rb +23 -0
  31. data/factory_girl/lib/factory_girl/evaluator.rb +76 -0
  32. data/factory_girl/lib/factory_girl/evaluator_class_definer.rb +20 -0
  33. data/factory_girl/lib/factory_girl/factory.rb +162 -0
  34. data/factory_girl/lib/factory_girl/factory_runner.rb +33 -0
  35. data/factory_girl/lib/factory_girl/find_definitions.rb +25 -0
  36. data/factory_girl/lib/factory_girl/linter.rb +47 -0
  37. data/factory_girl/lib/factory_girl/null_factory.rb +18 -0
  38. data/factory_girl/lib/factory_girl/null_object.rb +24 -0
  39. data/factory_girl/lib/factory_girl/registry.rb +38 -0
  40. data/factory_girl/lib/factory_girl/reload.rb +8 -0
  41. data/factory_girl/lib/factory_girl/sequence.rb +62 -0
  42. data/factory_girl/lib/factory_girl/strategy/attributes_for.rb +13 -0
  43. data/factory_girl/lib/factory_girl/strategy/build.rb +15 -0
  44. data/factory_girl/lib/factory_girl/strategy/create.rb +18 -0
  45. data/factory_girl/lib/factory_girl/strategy/null.rb +11 -0
  46. data/factory_girl/lib/factory_girl/strategy/stub.rb +73 -0
  47. data/factory_girl/lib/factory_girl/strategy_calculator.rb +26 -0
  48. data/factory_girl/lib/factory_girl/strategy_syntax_method_registrar.rb +46 -0
  49. data/factory_girl/lib/factory_girl/syntax.rb +7 -0
  50. data/factory_girl/lib/factory_girl/syntax/default.rb +76 -0
  51. data/factory_girl/lib/factory_girl/syntax/methods.rb +95 -0
  52. data/factory_girl/lib/factory_girl/syntax_runner.rb +6 -0
  53. data/factory_girl/lib/factory_girl/trait.rb +30 -0
  54. data/factory_girl/lib/factory_girl/version.rb +3 -0
  55. data/lib/opal-factory_girl.rb +16 -0
  56. data/lib/opal/factory_girl/version.rb +8 -0
  57. data/opal/opal-factory_girl.rb +184 -0
  58. data/opal/opal/active_support/inflector/methods.rb +395 -0
  59. metadata +142 -0
@@ -0,0 +1,7 @@
1
+ require 'factory_girl/syntax/methods'
2
+ require 'factory_girl/syntax/default'
3
+
4
+ module FactoryGirl
5
+ module Syntax
6
+ end
7
+ end
@@ -0,0 +1,76 @@
1
+ module FactoryGirl
2
+ module Syntax
3
+ module Default
4
+ include Methods
5
+
6
+ def define(&block)
7
+ DSL.run(block)
8
+ end
9
+
10
+ def modify(&block)
11
+ ModifyDSL.run(block)
12
+ end
13
+
14
+ class DSL
15
+ def factory(name, options = {}, &block)
16
+ factory = Factory.new(name, options)
17
+ proxy = FactoryGirl::DefinitionProxy.new(factory.definition)
18
+ proxy.instance_eval(&block) if block_given?
19
+
20
+ FactoryGirl.register_factory(factory)
21
+
22
+ proxy.child_factories.each do |(child_name, child_options, child_block)|
23
+ parent_factory = child_options.delete(:parent) || name
24
+ factory(child_name, child_options.merge(parent: parent_factory), &child_block)
25
+ end
26
+ end
27
+
28
+ def sequence(name, *args, &block)
29
+ FactoryGirl.register_sequence(Sequence.new(name, *args, &block))
30
+ end
31
+
32
+ def trait(name, &block)
33
+ FactoryGirl.register_trait(Trait.new(name, &block))
34
+ end
35
+
36
+ def to_create(&block)
37
+ FactoryGirl.to_create(&block)
38
+ end
39
+
40
+ def skip_create
41
+ FactoryGirl.skip_create
42
+ end
43
+
44
+ def initialize_with(&block)
45
+ FactoryGirl.initialize_with(&block)
46
+ end
47
+
48
+ def self.run(block)
49
+ new.instance_eval(&block)
50
+ end
51
+
52
+ delegate :before, :after, :callback, to: :configuration
53
+
54
+ private
55
+
56
+ def configuration
57
+ FactoryGirl.configuration
58
+ end
59
+ end
60
+
61
+ class ModifyDSL
62
+ def factory(name, options = {}, &block)
63
+ factory = FactoryGirl.factory_by_name(name)
64
+ proxy = FactoryGirl::DefinitionProxy.new(factory.definition.overridable)
65
+ proxy.instance_eval(&block)
66
+ end
67
+
68
+ def self.run(block)
69
+ new.instance_eval(&block)
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ extend Syntax::Default
76
+ end
@@ -0,0 +1,95 @@
1
+ module FactoryGirl
2
+ module Syntax
3
+ ## This module is a container for all strategy methods provided by
4
+ ## FactoryGirl. This includes all the default strategies provided ({Methods#build},
5
+ ## {Methods#create}, {Methods#build_stubbed}, and {Methods#attributes_for}), as well as
6
+ ## the complementary *_list methods.
7
+ ## @example singular factory execution
8
+ ## # basic use case
9
+ ## build(:completed_order)
10
+ ##
11
+ ## # factory yielding its result to a block
12
+ ## create(:post) do |post|
13
+ ## create(:comment, post: post)
14
+ ## end
15
+ ##
16
+ ## # factory with attribute override
17
+ ## attributes_for(:post, title: "I love Ruby!")
18
+ ##
19
+ ## # factory with traits and attribute override
20
+ ## build_stubbed(:user, :admin, :male, name: "John Doe")
21
+ ##
22
+ ## @example multiple factory execution
23
+ ## # basic use case
24
+ ## build_list(:completed_order, 2)
25
+ ## create_list(:completed_order, 2)
26
+ ##
27
+ ## # factory with attribute override
28
+ ## attributes_for_list(:post, 4, title: "I love Ruby!")
29
+ ##
30
+ ## # factory with traits and attribute override
31
+ ## build_stubbed_list(:user, 15, :admin, :male, name: "John Doe")
32
+ module Methods
33
+ # @!parse FactoryGirl.register_default_strategies
34
+ # @!method build(name, *traits_and_overrides, &block)
35
+ # (see #strategy_method)
36
+ # Builds a registered factory by name.
37
+ # @return [Object] instantiated object defined by the factory
38
+
39
+ # @!method create(name, *traits_and_overrides, &block)
40
+ # (see #strategy_method)
41
+ # Creates a registered factory by name.
42
+ # @return [Object] instantiated object defined by the factory
43
+
44
+ # @!method build_stubbed(name, *traits_and_overrides, &block)
45
+ # (see #strategy_method)
46
+ # Builds a stubbed registered factory by name.
47
+ # @return [Object] instantiated object defined by the factory
48
+
49
+ # @!method attributes_for(name, *traits_and_overrides, &block)
50
+ # (see #strategy_method)
51
+ # Generates a hash of attributes for a registered factory by name.
52
+ # @return [Hash] hash of attributes for the factory
53
+
54
+ # @!method build_list(name, amount, *traits_and_overrides)
55
+ # (see #strategy_method_list)
56
+ # @return [Array] array of built objects defined by the factory
57
+
58
+ # @!method create_list(name, amount, *traits_and_overrides)
59
+ # (see #strategy_method_list)
60
+ # @return [Array] array of created objects defined by the factory
61
+
62
+ # @!method build_stubbed_list(name, amount, *traits_and_overrides)
63
+ # (see #strategy_method_list)
64
+ # @return [Array] array of stubbed objects defined by the factory
65
+
66
+ # @!method attributes_for_list(name, amount, *traits_and_overrides)
67
+ # (see #strategy_method_list)
68
+ # @return [Array<Hash>] array of attribute hashes for the factory
69
+
70
+ # @!method strategy_method
71
+ # @!visibility private
72
+ # @param [Symbol] name name of the factory to build
73
+ # @param [Array<Symbol, Symbol, Hash>] traits_and_overrides splat args traits and a hash of overrides
74
+ # @param [Proc] block block to be executed
75
+
76
+ # @!method strategy_method_list
77
+ # @!visibility private
78
+ # @param [Symbol] name name of the factory to execute
79
+ # @param [Integer] amount the number of instances to execute
80
+ # @param [Array<Symbol, Symbol, Hash>] traits_and_overrides splat args traits and a hash of overrides
81
+
82
+ # Generates and returns the next value in a sequence.
83
+ #
84
+ # Arguments:
85
+ # name: (Symbol)
86
+ # The name of the sequence that a value should be generated for.
87
+ #
88
+ # Returns:
89
+ # The next value in the sequence. (Object)
90
+ def generate(name)
91
+ FactoryGirl.sequence_by_name(name).next
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,6 @@
1
+ module FactoryGirl
2
+ # @api private
3
+ class SyntaxRunner
4
+ include Syntax::Methods
5
+ end
6
+ end
@@ -0,0 +1,30 @@
1
+ module FactoryGirl
2
+ # @api private
3
+ class Trait
4
+ attr_reader :name, :definition
5
+
6
+ def initialize(name, &block)
7
+ @name = name
8
+ @block = block
9
+ @definition = Definition.new(@name)
10
+
11
+ proxy = FactoryGirl::DefinitionProxy.new(@definition)
12
+ proxy.instance_eval(&@block) if block_given?
13
+ end
14
+
15
+ delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
16
+ :callbacks, :attributes, to: :@definition
17
+
18
+ def names
19
+ [@name]
20
+ end
21
+
22
+ def ==(other)
23
+ name == other.name &&
24
+ block == other.block
25
+ end
26
+
27
+ protected
28
+ attr_reader :block
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module FactoryGirl
2
+ VERSION = '4.5.0'
3
+ end
@@ -0,0 +1,16 @@
1
+ [
2
+ 'jruby/synchronized',
3
+ 'monitor',
4
+ 'thread_safe/jruby_cache_backend',
5
+ 'atomic',
6
+ 'jruby',
7
+ 'logger',
8
+ 'active_support/inflector/methods', # has an incompatible regex in it
9
+ ].each { |r| Opal::Processor.stub_file r }
10
+
11
+
12
+ # Just register our opal code path with opal build tools
13
+ Opal.append_path File.expand_path('../../opal', __FILE__)
14
+ Opal.append_path File.expand_path('../../factory_girl/lib', __FILE__)
15
+ require 'opal-activesupport'
16
+ Opal.use_gem 'activesupport'
@@ -0,0 +1,8 @@
1
+ require 'factory_girl/version'
2
+
3
+ module Opal
4
+ module FactoryGirl
5
+ # Add a minor version to the end in case there are opal specific issues to fix
6
+ VERSION = "#{::FactoryGirl::VERSION}.3"
7
+ end
8
+ end
@@ -0,0 +1,184 @@
1
+ module Mutex_m
2
+ def synchronize
3
+ yield
4
+ end
5
+ end
6
+
7
+ require 'active_support/core_ext/module/delegation'
8
+ require 'active_support/inflector'
9
+ require 'opal/active_support/inflector/methods'
10
+ require 'active_support/core_ext/string/inflections'
11
+ require 'active_support/core_ext/string'
12
+ require 'active_support/notifications/fanout'
13
+
14
+ class String
15
+ def humanize
16
+ ActiveSupport::Inflector.humanize(self)
17
+ end
18
+ end
19
+
20
+ class ActiveSupport::Inflector::Inflections
21
+ def humans
22
+ @humans ||= []
23
+ end
24
+
25
+ def acronyms
26
+ @acronyms ||= {}
27
+ end
28
+
29
+ def acronym_regex
30
+ @acronym_regex ||= /(?=a)b/
31
+ end
32
+
33
+ def human(rule, replacement)
34
+ @humans.prepend([rule, replacement])
35
+ end
36
+
37
+ def acronym(word)
38
+ a = acronyms
39
+ _ = acronym_regex
40
+ a[word.downcase] = word
41
+ @acronym_regex = /#{a.values.join("|")}/
42
+ end
43
+ end
44
+
45
+ module ActiveSupport
46
+ module Notifications
47
+ # This is a default queue implementation that ships with Notifications.
48
+ # It just pushes events to all registered log subscribers.
49
+ #
50
+ # This class is thread safe. All methods are reentrant.
51
+ class Fanout
52
+ #def subscribe(pattern = nil, block = Proc.new)
53
+ # Opal doesn't like block without &block and Proc.new isn't valid anyways
54
+ def subscribe(pattern = nil, &block)
55
+ subscriber = Subscribers.new pattern, block
56
+ synchronize do
57
+ @subscribers << subscriber
58
+ @listeners_for.clear
59
+ end
60
+ subscriber
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ require 'factory_girl'
67
+
68
+ # Opal didn't seem like like synchronize { super }, so removed sync, probably super w/ args inside a block
69
+ module ThreadSafe
70
+ class SynchronizedCacheBackend
71
+ def [](key)
72
+ super
73
+ end
74
+
75
+ def []=(key, value)
76
+ super
77
+ end
78
+
79
+ def compute_if_absent(key)
80
+ super
81
+ end
82
+
83
+ def compute_if_present(key)
84
+ super
85
+ end
86
+
87
+ def compute(key)
88
+ super
89
+ end
90
+
91
+ def merge_pair(key, value)
92
+ super
93
+ end
94
+
95
+ def replace_pair(key, old_value, new_value)
96
+ super
97
+ end
98
+
99
+ def replace_if_exists(key, new_value)
100
+ super
101
+ end
102
+
103
+ def get_and_set(key, value)
104
+ super
105
+ end
106
+
107
+ def key?(key)
108
+ super
109
+ end
110
+
111
+ def value?(value)
112
+ super
113
+ end
114
+
115
+ def delete(key)
116
+ super
117
+ end
118
+
119
+ def delete_pair(key, value)
120
+ super
121
+ end
122
+
123
+ def clear
124
+ super
125
+ end
126
+
127
+ def size
128
+ super
129
+ end
130
+
131
+ def get_or_default(key, default_value)
132
+ super
133
+ end
134
+
135
+ private
136
+ def dupped_backend
137
+ super
138
+ end
139
+ end
140
+ end
141
+
142
+ module FactoryGirl
143
+ class Decorator
144
+ class NewConstructor < Decorator
145
+ def build_class_accessor
146
+ @build_class
147
+ end
148
+
149
+ # For some reason, the instance_variable_get was not working
150
+ #delegate :new, to: :@build_class
151
+ delegate :new, to: :build_class_accessor
152
+ end
153
+ end
154
+ end
155
+
156
+
157
+ module FactoryGirl
158
+ class AttributeAssigner
159
+ def instance_builder_set(&instance_builder)
160
+ @instance_builder = instance_builder
161
+ end
162
+ end
163
+
164
+ # @api private
165
+ class Factory
166
+ def run(build_strategy, overrides, &block)
167
+ block ||= ->(result) { result }
168
+ compile
169
+
170
+ strategy = StrategyCalculator.new(build_strategy).strategy.new
171
+
172
+ evaluator = evaluator_class.new(strategy, overrides.symbolize_keys)
173
+ constr = compiled_constructor
174
+ attribute_assigner = AttributeAssigner.new(evaluator, build_class, &constr)
175
+ # Opal issues with passing a block reference in a constructor
176
+ attribute_assigner.instance_builder_set(&constr)
177
+
178
+ evaluation = Evaluation.new(attribute_assigner, compiled_to_create)
179
+ evaluation.add_observer(CallbacksObserver.new(callbacks, evaluator))
180
+
181
+ strategy.result(evaluation).tap(&block)
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,395 @@
1
+ require 'active_support/inflections'
2
+
3
+ module ActiveSupport
4
+ # The Inflector transforms words from singular to plural, class names to table
5
+ # names, modularized class names to ones without, and class names to foreign
6
+ # keys. The default inflections for pluralization, singularization, and
7
+ # uncountable words are kept in inflections.rb.
8
+ #
9
+ # The Rails core team has stated patches for the inflections library will not
10
+ # be accepted in order to avoid breaking legacy applications which may be
11
+ # relying on errant inflections. If you discover an incorrect inflection and
12
+ # require it for your application or wish to define rules for languages other
13
+ # than English, please correct or add them yourself (explained below).
14
+ module Inflector
15
+ extend self
16
+
17
+ # Returns the plural form of the word in the string.
18
+ #
19
+ # If passed an optional +locale+ parameter, the word will be
20
+ # pluralized using rules defined for that language. By default,
21
+ # this parameter is set to <tt>:en</tt>.
22
+ #
23
+ # pluralize('post') # => "posts"
24
+ # pluralize('octopus') # => "octopi"
25
+ # pluralize('sheep') # => "sheep"
26
+ # pluralize('words') # => "words"
27
+ # pluralize('CamelOctopus') # => "CamelOctopi"
28
+ # pluralize('ley', :es) # => "leyes"
29
+ def pluralize(word, locale = :en)
30
+ apply_inflections(word, inflections(locale).plurals)
31
+ end
32
+
33
+ # The reverse of #pluralize, returns the singular form of a word in a
34
+ # string.
35
+ #
36
+ # If passed an optional +locale+ parameter, the word will be
37
+ # singularized using rules defined for that language. By default,
38
+ # this parameter is set to <tt>:en</tt>.
39
+ #
40
+ # singularize('posts') # => "post"
41
+ # singularize('octopi') # => "octopus"
42
+ # singularize('sheep') # => "sheep"
43
+ # singularize('word') # => "word"
44
+ # singularize('CamelOctopi') # => "CamelOctopus"
45
+ # singularize('leyes', :es) # => "ley"
46
+ def singularize(word, locale = :en)
47
+ apply_inflections(word, inflections(locale).singulars)
48
+ end
49
+
50
+ # Converts strings to UpperCamelCase.
51
+ # If the +uppercase_first_letter+ parameter is set to false, then produces
52
+ # lowerCamelCase.
53
+ #
54
+ # Also converts '/' to '::' which is useful for converting
55
+ # paths to namespaces.
56
+ #
57
+ # camelize('active_model') # => "ActiveModel"
58
+ # camelize('active_model', false) # => "activeModel"
59
+ # camelize('active_model/errors') # => "ActiveModel::Errors"
60
+ # camelize('active_model/errors', false) # => "activeModel::Errors"
61
+ #
62
+ # As a rule of thumb you can think of +camelize+ as the inverse of
63
+ # #underscore, though there are cases where that does not hold:
64
+ #
65
+ # camelize(underscore('SSLError')) # => "SslError"
66
+ def camelize(term, uppercase_first_letter = true)
67
+ string = term.to_s
68
+ if uppercase_first_letter
69
+ string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize }
70
+ else
71
+ string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
72
+ end
73
+ string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
74
+ string.gsub!('/'.freeze, '::'.freeze)
75
+ string
76
+ end
77
+
78
+ # Makes an underscored, lowercase form from the expression in the string.
79
+ #
80
+ # Changes '::' to '/' to convert namespaces to paths.
81
+ #
82
+ # underscore('ActiveModel') # => "active_model"
83
+ # underscore('ActiveModel::Errors') # => "active_model/errors"
84
+ #
85
+ # As a rule of thumb you can think of +underscore+ as the inverse of
86
+ # #camelize, though there are cases where that does not hold:
87
+ #
88
+ # camelize(underscore('SSLError')) # => "SslError"
89
+ def underscore(camel_cased_word)
90
+ return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
91
+ word = camel_cased_word.to_s.gsub('::'.freeze, '/'.freeze)
92
+ word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'.freeze }#{$2.downcase}" }
93
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
94
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
95
+ word.tr!("-".freeze, "_".freeze)
96
+ word.downcase!
97
+ word
98
+ end
99
+
100
+ # Tweaks an attribute name for display to end users.
101
+ #
102
+ # Specifically, performs these transformations:
103
+ #
104
+ # * Applies human inflection rules to the argument.
105
+ # * Deletes leading underscores, if any.
106
+ # * Removes a "_id" suffix if present.
107
+ # * Replaces underscores with spaces, if any.
108
+ # * Downcases all words except acronyms.
109
+ # * Capitalizes the first word.
110
+ #
111
+ # The capitalization of the first word can be turned off by setting the
112
+ # +:capitalize+ option to false (default is true).
113
+ #
114
+ # humanize('employee_salary') # => "Employee salary"
115
+ # humanize('author_id') # => "Author"
116
+ # humanize('author_id', capitalize: false) # => "author"
117
+ # humanize('_id') # => "Id"
118
+ #
119
+ # If "SSL" was defined to be an acronym:
120
+ #
121
+ # humanize('ssl_error') # => "SSL error"
122
+ #
123
+ def humanize(lower_case_and_underscored_word, options = {})
124
+ result = lower_case_and_underscored_word.to_s.dup
125
+
126
+ # no humans attr exists on inflections, need to port that over
127
+
128
+ # opal - string mutation
129
+ inflections.humans.each { |(rule, replacement)| break if (result = result.sub(rule, replacement)) }
130
+
131
+ # opal - \A and \z not supported
132
+ #result = result.sub(/\A_+/, ''.freeze)
133
+ result = result.sub(/^_+/, ''.freeze)
134
+ #result = result.sub(/_id\z/, ''.freeze)
135
+ result = result.sub(/_id$/, ''.freeze)
136
+ result = result.tr('_'.freeze, ' '.freeze)
137
+
138
+ result = result.gsub(/([a-z\d]*)/i) do |match|
139
+ "#{inflections.acronyms[match] || match.downcase}"
140
+ end
141
+
142
+ if options.fetch(:capitalize, true)
143
+ #result = result.sub(/\A\w/) { |match| match.upcase }
144
+ result = result.sub(/^\w/) { |match| match.upcase }
145
+ end
146
+
147
+ result
148
+ end
149
+
150
+ # Capitalizes all the words and replaces some characters in the string to
151
+ # create a nicer looking title. +titleize+ is meant for creating pretty
152
+ # output. It is not used in the Rails internals.
153
+ #
154
+ # +titleize+ is also aliased as +titlecase+.
155
+ #
156
+ # titleize('man from the boondocks') # => "Man From The Boondocks"
157
+ # titleize('x-men: the last stand') # => "X Men: The Last Stand"
158
+ # titleize('TheManWithoutAPast') # => "The Man Without A Past"
159
+ # titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
160
+ def titleize(word)
161
+ # negative lookbehind doesn't work in Firefox / Safari
162
+ # humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { |match| match.capitalize }
163
+ humanized = humanize(underscore(word))
164
+ humanized.reverse.gsub(/[a-z](?!['’`])\b/) { |match| match.capitalize }.reverse
165
+ end
166
+
167
+ # Creates the name of a table like Rails does for models to table names.
168
+ # This method uses the #pluralize method on the last word in the string.
169
+ #
170
+ # tableize('RawScaledScorer') # => "raw_scaled_scorers"
171
+ # tableize('ham_and_egg') # => "ham_and_eggs"
172
+ # tableize('fancyCategory') # => "fancy_categories"
173
+ def tableize(class_name)
174
+ pluralize(underscore(class_name))
175
+ end
176
+
177
+ # Creates a class name from a plural table name like Rails does for table
178
+ # names to models. Note that this returns a string and not a Class (To
179
+ # convert to an actual class follow +classify+ with #constantize).
180
+ #
181
+ # classify('ham_and_eggs') # => "HamAndEgg"
182
+ # classify('posts') # => "Post"
183
+ #
184
+ # Singular names are not handled correctly:
185
+ #
186
+ # classify('calculus') # => "Calculu"
187
+ def classify(table_name)
188
+ # strip out any leading schema name
189
+ camelize(singularize(table_name.to_s.sub(/.*\./, ''.freeze)))
190
+ end
191
+
192
+ # Replaces underscores with dashes in the string.
193
+ #
194
+ # dasherize('puni_puni') # => "puni-puni"
195
+ def dasherize(underscored_word)
196
+ underscored_word.tr('_'.freeze, '-'.freeze)
197
+ end
198
+
199
+ # Removes the module part from the expression in the string.
200
+ #
201
+ # demodulize('ActiveRecord::CoreExtensions::String::Inflections') # => "Inflections"
202
+ # demodulize('Inflections') # => "Inflections"
203
+ # demodulize('::Inflections') # => "Inflections"
204
+ # demodulize('') # => ""
205
+ #
206
+ # See also #deconstantize.
207
+ def demodulize(path)
208
+ path = path.to_s
209
+ if i = path.rindex('::')
210
+ path[(i+2)..-1]
211
+ else
212
+ path
213
+ end
214
+ end
215
+
216
+ # Removes the rightmost segment from the constant expression in the string.
217
+ #
218
+ # deconstantize('Net::HTTP') # => "Net"
219
+ # deconstantize('::Net::HTTP') # => "::Net"
220
+ # deconstantize('String') # => ""
221
+ # deconstantize('::String') # => ""
222
+ # deconstantize('') # => ""
223
+ #
224
+ # See also #demodulize.
225
+ def deconstantize(path)
226
+ path.to_s[0, path.rindex('::') || 0] # implementation based on the one in facets' Module#spacename
227
+ end
228
+
229
+ # Creates a foreign key name from a class name.
230
+ # +separate_class_name_and_id_with_underscore+ sets whether
231
+ # the method should put '_' between the name and 'id'.
232
+ #
233
+ # foreign_key('Message') # => "message_id"
234
+ # foreign_key('Message', false) # => "messageid"
235
+ # foreign_key('Admin::Post') # => "post_id"
236
+ def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
237
+ underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
238
+ end
239
+
240
+ # Tries to find a constant with the name specified in the argument string.
241
+ #
242
+ # 'Module'.constantize # => Module
243
+ # 'Foo::Bar'.constantize # => Foo::Bar
244
+ #
245
+ # The name is assumed to be the one of a top-level constant, no matter
246
+ # whether it starts with "::" or not. No lexical context is taken into
247
+ # account:
248
+ #
249
+ # C = 'outside'
250
+ # module M
251
+ # C = 'inside'
252
+ # C # => 'inside'
253
+ # 'C'.constantize # => 'outside', same as ::C
254
+ # end
255
+ #
256
+ # NameError is raised when the name is not in CamelCase or the constant is
257
+ # unknown.
258
+ def constantize(camel_cased_word)
259
+ names = camel_cased_word.split('::'.freeze)
260
+
261
+ # Trigger a built-in NameError exception including the ill-formed constant in the message.
262
+ Object.const_get(camel_cased_word) if names.empty?
263
+
264
+ # Remove the first blank element in case of '::ClassName' notation.
265
+ names.shift if names.size > 1 && names.first.empty?
266
+
267
+ names.inject(Object) do |constant, name|
268
+ if constant == Object
269
+ constant.const_get(name)
270
+ else
271
+ candidate = constant.const_get(name)
272
+ next candidate if constant.const_defined?(name, false)
273
+ next candidate unless Object.const_defined?(name)
274
+
275
+ # Go down the ancestors to check if it is owned directly. The check
276
+ # stops when we reach Object or the end of ancestors tree.
277
+ constant = constant.ancestors.inject do |const, ancestor|
278
+ break const if ancestor == Object
279
+ break ancestor if ancestor.const_defined?(name, false)
280
+ const
281
+ end
282
+
283
+ # owner is in Object, so raise
284
+ constant.const_get(name, false)
285
+ end
286
+ end
287
+ end
288
+
289
+ # Tries to find a constant with the name specified in the argument string.
290
+ #
291
+ # safe_constantize('Module') # => Module
292
+ # safe_constantize('Foo::Bar') # => Foo::Bar
293
+ #
294
+ # The name is assumed to be the one of a top-level constant, no matter
295
+ # whether it starts with "::" or not. No lexical context is taken into
296
+ # account:
297
+ #
298
+ # C = 'outside'
299
+ # module M
300
+ # C = 'inside'
301
+ # C # => 'inside'
302
+ # safe_constantize('C') # => 'outside', same as ::C
303
+ # end
304
+ #
305
+ # +nil+ is returned when the name is not in CamelCase or the constant (or
306
+ # part of it) is unknown.
307
+ #
308
+ # safe_constantize('blargle') # => nil
309
+ # safe_constantize('UnknownModule') # => nil
310
+ # safe_constantize('UnknownModule::Foo::Bar') # => nil
311
+ def safe_constantize(camel_cased_word)
312
+ constantize(camel_cased_word)
313
+ rescue NameError => e
314
+ raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
315
+ e.name.to_s == camel_cased_word.to_s)
316
+ rescue ArgumentError => e
317
+ raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
318
+ end
319
+
320
+ # Returns the suffix that should be added to a number to denote the position
321
+ # in an ordered sequence such as 1st, 2nd, 3rd, 4th.
322
+ #
323
+ # ordinal(1) # => "st"
324
+ # ordinal(2) # => "nd"
325
+ # ordinal(1002) # => "nd"
326
+ # ordinal(1003) # => "rd"
327
+ # ordinal(-11) # => "th"
328
+ # ordinal(-1021) # => "st"
329
+ def ordinal(number)
330
+ abs_number = number.to_i.abs
331
+
332
+ if (11..13).include?(abs_number % 100)
333
+ "th"
334
+ else
335
+ case abs_number % 10
336
+ when 1;
337
+ "st"
338
+ when 2;
339
+ "nd"
340
+ when 3;
341
+ "rd"
342
+ else
343
+ "th"
344
+ end
345
+ end
346
+ end
347
+
348
+ # Turns a number into an ordinal string used to denote the position in an
349
+ # ordered sequence such as 1st, 2nd, 3rd, 4th.
350
+ #
351
+ # ordinalize(1) # => "1st"
352
+ # ordinalize(2) # => "2nd"
353
+ # ordinalize(1002) # => "1002nd"
354
+ # ordinalize(1003) # => "1003rd"
355
+ # ordinalize(-11) # => "-11th"
356
+ # ordinalize(-1021) # => "-1021st"
357
+ def ordinalize(number)
358
+ "#{number}#{ordinal(number)}"
359
+ end
360
+
361
+ private
362
+
363
+ # Mounts a regular expression, returned as a string to ease interpolation,
364
+ # that will match part by part the given constant.
365
+ #
366
+ # const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
367
+ # const_regexp("::") # => "::"
368
+ def const_regexp(camel_cased_word) #:nodoc:
369
+ parts = camel_cased_word.split("::".freeze)
370
+
371
+ return Regexp.escape(camel_cased_word) if parts.blank?
372
+
373
+ last = parts.pop
374
+
375
+ parts.reverse.inject(last) do |acc, part|
376
+ part.empty? ? acc : "#{part}(::#{acc})?"
377
+ end
378
+ end
379
+
380
+ # Applies inflection rules for +singularize+ and +pluralize+.
381
+ #
382
+ # apply_inflections('post', inflections.plurals) # => "posts"
383
+ # apply_inflections('posts', inflections.singulars) # => "post"
384
+ def apply_inflections(word, rules)
385
+ result = word.to_s.dup
386
+
387
+ if word.empty? || inflections.uncountables.uncountable?(result)
388
+ result
389
+ else
390
+ rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
391
+ result
392
+ end
393
+ end
394
+ end
395
+ end