syncwise_api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +1 -0
  9. data/lib/syncwise_api/client.rb +47 -0
  10. data/lib/syncwise_api/errors.rb +93 -0
  11. data/lib/syncwise_api/ext/core_ext.rb +176 -0
  12. data/lib/syncwise_api/ext/inflections.rb +66 -0
  13. data/lib/syncwise_api/ext/inflector/inflections.rb +177 -0
  14. data/lib/syncwise_api/ext/inflector_methods.rb +62 -0
  15. data/lib/syncwise_api/ext/string_encoding.rb +12 -0
  16. data/lib/syncwise_api/mixins/mixins.rb +1 -0
  17. data/lib/syncwise_api/mixins/request_builder.rb +23 -0
  18. data/lib/syncwise_api/mixins/request_sender.rb +11 -0
  19. data/lib/syncwise_api/mixins/request_signer.rb +20 -0
  20. data/lib/syncwise_api/requests/V1_0/assign_device_create.rb +19 -0
  21. data/lib/syncwise_api/requests/V1_0/base.rb +115 -0
  22. data/lib/syncwise_api/requests/V1_0/device_details.rb +19 -0
  23. data/lib/syncwise_api/requests/V1_0/device_list.rb +19 -0
  24. data/lib/syncwise_api/requests/V1_0/device_settings_details.rb +19 -0
  25. data/lib/syncwise_api/requests/V1_0/device_settings_edit.rb +19 -0
  26. data/lib/syncwise_api/requests/V1_0/device_subscribe.rb +19 -0
  27. data/lib/syncwise_api/requests/V1_0/device_unsubscribe.rb +19 -0
  28. data/lib/syncwise_api/requests/V1_0/driver_speed_report.rb +19 -0
  29. data/lib/syncwise_api/requests/V1_0/obd_vehicle_details.rb +19 -0
  30. data/lib/syncwise_api/requests/V1_0/trip_event_details.rb +19 -0
  31. data/lib/syncwise_api/requests/V1_0/user_login.rb +26 -0
  32. data/lib/syncwise_api/requests/V1_0/user_subscribe_settings_details.rb +19 -0
  33. data/lib/syncwise_api/requests/V1_0/vehicle_gauge_information.rb +19 -0
  34. data/lib/syncwise_api/requests/V1_0/vehicle_idling_history.rb +19 -0
  35. data/lib/syncwise_api/requests/requests.rb +2 -0
  36. data/lib/syncwise_api/responses/V1_0/base.rb +35 -0
  37. data/lib/syncwise_api/responses/V1_0/standard.rb +9 -0
  38. data/lib/syncwise_api/responses/responses.rb +1 -0
  39. data/lib/syncwise_api/service_utils/crypto/hmac_sha256.rb +15 -0
  40. data/lib/syncwise_api/service_utils/encoders/base64.rb +16 -0
  41. data/lib/syncwise_api/service_utils/encoders/json.rb +21 -0
  42. data/lib/syncwise_api/service_utils/http.rb +34 -0
  43. data/lib/syncwise_api/service_utils/parsers/json.rb +55 -0
  44. data/lib/syncwise_api/service_utils/service_utils.rb +2 -0
  45. data/lib/syncwise_api/service_utils/time_stamper.rb +13 -0
  46. data/lib/syncwise_api/version.rb +3 -0
  47. data/lib/syncwise_api.rb +30 -0
  48. data/syncwise_api.gemspec +27 -0
  49. data/tester.rb +10 -0
  50. metadata +162 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d5ab37738b62b0ea99540366cc22ebe5352a6758
4
+ data.tar.gz: 50b3e3a806577539e51e8dbb7c0d7d64bea67530
5
+ SHA512:
6
+ metadata.gz: 460840491191c2bcb26381782446c568ac45126a24a4f2c1a24c80e401b9b19d0874c204706c64007ea7a2504eedfacfc35e18d0a3cd0c824cb31575bad56e61
7
+ data.tar.gz: 1a4992ebb5800beb11b5b12c9a00f86c4e759ec68bea7cbe1f0e9208957ef276d4a8325b62e34fc957f84a82caef384d05e9e7c69a64e095e79e423ecef6a2f1
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ bin/
19
+ .idea/
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ syncwise_api
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in syncwise_api.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Brendten Eickstaedt
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # SyncwiseApi
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'syncwise_api'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install syncwise_api
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,47 @@
1
+ module SyncwiseApi
2
+ class Client
3
+
4
+ def initialize(username, password)
5
+ @username = username
6
+ @password = password
7
+ login
8
+ end
9
+
10
+ def make_request(action_code, params)
11
+ if action_code == :user_login
12
+ puts 'Login is done automatically when a new Client is created. Ignoring this call.'
13
+ else
14
+ action_code = action_code.camelize
15
+ if SyncwiseApi::Requests::V1_0.const_defined?(action_code)
16
+ params[:'Action Code'] = action_code
17
+ params[:'API Key'] = @username
18
+ params[:secretKey] = @secret_key
19
+ params[:accountId] = @account_id
20
+ request_class = SyncwiseApi::Requests::V1_0.const_get(action_code)
21
+ request = request_class.new(params)
22
+ response = request.send_request
23
+ else
24
+ puts 'Sorry, that\'s not a valid request type.'
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def login
32
+ begin
33
+ request = SyncwiseApi::Requests::V1_0::UserLogin.new({:'API Key' => @username, :password => @password, :secretKey => '', :accountId => ''})
34
+ response = request.send_request
35
+ if response.valid?
36
+ @secret_key = response.body_hash[:secret_key]
37
+ @account_id = response.body_hash[:account_id]
38
+ else
39
+ fail SyncwiseApi::Errors::ApiErrorCode.new(response, request, response.header_hash, response.body_hash)
40
+ end
41
+ rescue => e
42
+ SyncwiseApi::LOGGER.error e
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,93 @@
1
+ module SyncwiseApi
2
+ module Errors
3
+
4
+ class SyncwiseError < StandardError
5
+
6
+ end
7
+
8
+ class MissingInstanceVariable < SyncwiseError
9
+ def initialize(variable, mixin, receiver)
10
+ @variable = variable
11
+ @mixin = mixin
12
+ @receiver_inspect = receiver.inspect
13
+ super("Mixin #{@mixin} tried to use undefined instance variable #{@variable} in #{@receiver_inspect}")
14
+ end
15
+
16
+ attr_reader :variable, :mixin, :receiver_inspect
17
+ end
18
+
19
+ class InvalidParameters < SyncwiseError
20
+ def initialize(request_type, passed_params, required_params)
21
+ @request_type = request_type
22
+ @passed_params = passed_params
23
+ @required_params = required_params
24
+ super("#{@request_type} was called with params #{@passed_params}, but requires params #{@required_params}")
25
+ end
26
+
27
+ attr_reader :request_type, :passed_params, :required_params
28
+ end
29
+
30
+ class JSONParseError < SyncwiseError
31
+ def initialize(error)
32
+ @error = error
33
+ super("Error parsing JSON: #{@error}")
34
+ end
35
+
36
+ attr_reader :error
37
+ end
38
+
39
+ class JSONEncodeError < SyncwiseError
40
+ def initialize(object)
41
+ @object = object
42
+ super("Error encoding object into JSON. Object: #{@object.inspect}")
43
+ end
44
+
45
+ attr_reader :object
46
+ end
47
+
48
+ class HttpError < SyncwiseError
49
+ def initialize(error, request)
50
+ @error = error
51
+ @request = request
52
+ super("Http Error when trying to make request. Object: #{@error.inspect}, request: #{@request}")
53
+ end
54
+
55
+ attr_reader :error, :request
56
+ end
57
+
58
+ class SyncwiseApi::Errors::EmptyResponseBody < SyncwiseError
59
+ def initialize(resp, request, header)
60
+ @resp = resp
61
+ @request = request
62
+ @header = header
63
+ super("Api call returned with empty body. Response: #{@resp}, request: #{@request}, header: #{@header}")
64
+ end
65
+
66
+ attr_reader :resp, :request, :header
67
+ end
68
+
69
+ class SyncwiseApi::Errors::InvalidContentType < SyncwiseError
70
+ def initialize(resp, request, header)
71
+ @resp = resp
72
+ @request = request
73
+ @header = header
74
+ super("Api call returned an invalid Content-Type. Response: #{@resp}, request: #{@request}, header: #{@header}")
75
+ end
76
+
77
+ attr_reader :resp, :request, :header
78
+ end
79
+
80
+ class SyncwiseApi::Errors::ApiErrorCode < SyncwiseError
81
+ def initialize(resp, request, header, body)
82
+ @resp = resp
83
+ @request = request
84
+ @header = header
85
+ @body = body
86
+ super("Api call returned a Syncwise Error Code. Response: #{@resp}, request: #{@request}, header: #{@header}, body: #{@body}")
87
+ end
88
+
89
+ attr_reader :resp, :request, :header, :body
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,176 @@
1
+ # encoding: utf-8
2
+ require_relative 'string_encoding'
3
+ require_relative 'inflector_methods'
4
+
5
+ # so there are some things from Rails I love, and have a hard time living without when using PORO.
6
+ # i'm adding them back here. thanks, Rails Core team ;)
7
+ class Hash
8
+ def deep_symbolize_keys
9
+ result = {}
10
+ each do |key, value|
11
+ result[(key.underscore.dehumanize.to_sym rescue key)] = value.is_a?(Hash) ? value.deep_symbolize_keys : value
12
+ end
13
+ result
14
+ end
15
+
16
+ alias_method :symbolize_keys, :deep_symbolize_keys
17
+ end
18
+
19
+ class Object
20
+ # An object is blank if it's false, empty, or a whitespace string.
21
+ # For example, "", " ", +nil+, [], and {} are all blank.
22
+ #
23
+ # This simplifies:
24
+ #
25
+ # if address.nil? || address.empty?
26
+ #
27
+ # ...to:
28
+ #
29
+ # if address.blank?
30
+ def blank?
31
+ respond_to?(:empty?) ? empty? : !self
32
+ end
33
+
34
+ # An object is present if it's not <tt>blank?</tt>.
35
+ def present?
36
+ !blank?
37
+ end
38
+
39
+ # Returns object if it's <tt>present?</tt> otherwise returns +nil+.
40
+ # <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
41
+ #
42
+ # This is handy for any representation of objects where blank is the same
43
+ # as not present at all. For example, this simplifies a common check for
44
+ # HTTP POST/query parameters:
45
+ #
46
+ # state = params[:state] if params[:state].present?
47
+ # country = params[:country] if params[:country].present?
48
+ # region = state || country || 'US'
49
+ #
50
+ # ...becomes:
51
+ #
52
+ # region = params[:state].presence || params[:country].presence || 'US'
53
+ def presence
54
+ self if present?
55
+ end
56
+
57
+ # Returns just the class name as a String, without namespace/modules
58
+ # For example, this method called on class This::That::AndTheOtherThing will
59
+ # return AndTheOtherThing
60
+ def unqualified_class
61
+ self.class.to_s.split('::').last
62
+ end
63
+ end
64
+
65
+ class NilClass
66
+ # +nil+ is blank:
67
+ #
68
+ # nil.blank? # => true
69
+ #
70
+ def blank?
71
+ true
72
+ end
73
+ end
74
+
75
+ class FalseClass
76
+ # +false+ is blank:
77
+ #
78
+ # false.blank? # => true
79
+ #
80
+ def blank?
81
+ true
82
+ end
83
+ end
84
+
85
+ class TrueClass
86
+ # +true+ is not blank:
87
+ #
88
+ # true.blank? # => false
89
+ #
90
+ def blank?
91
+ false
92
+ end
93
+ end
94
+
95
+ class Array
96
+ # An array is blank if it's empty:
97
+ #
98
+ # [].blank? # => true
99
+ # [1,2,3].blank? # => false
100
+ #
101
+ alias_method :blank?, :empty?
102
+ end
103
+
104
+ class Hash
105
+ # A hash is blank if it's empty:
106
+ #
107
+ # {}.blank? # => true
108
+ # {:key => 'value'}.blank? # => false
109
+ #
110
+ alias_method :blank?, :empty?
111
+ end
112
+
113
+ class String
114
+ # 0x3000: fullwidth whitespace
115
+ NON_WHITESPACE_REGEXP = %r![^\s#{[0x3000].pack("U")}]!
116
+
117
+ # A string is blank if it's empty or contains whitespaces only:
118
+ #
119
+ # "".blank? # => true
120
+ # " ".blank? # => true
121
+ # " ".blank? # => true
122
+ # " something here ".blank? # => false
123
+ #
124
+ def blank?
125
+ # 1.8 does not takes [:space:] properly
126
+ if encoding_aware?
127
+ self !~ /[^[:space:]]/
128
+ else
129
+ self !~ NON_WHITESPACE_REGEXP
130
+ end
131
+ end
132
+
133
+ def dehumanize
134
+ SyncwiseApi::Inflector.dehumanize(self)
135
+ end
136
+
137
+ def underscore
138
+ SyncwiseApi::Inflector.underscore(self)
139
+ end
140
+
141
+
142
+ # By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
143
+ # is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
144
+ #
145
+ # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
146
+ #
147
+ # "active_record".camelize # => "ActiveRecord"
148
+ # "active_record".camelize(:lower) # => "activeRecord"
149
+ # "active_record/errors".camelize # => "ActiveRecord::Errors"
150
+ # "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
151
+ def camelize(first_letter = :upper)
152
+ case first_letter
153
+ when :upper then SyncwiseApi::Inflector.camelize(self, true)
154
+ when :lower then SyncwiseApi::Inflector.camelize(self, false)
155
+ end
156
+ end
157
+ alias_method :camelcase, :camelize
158
+
159
+ end
160
+
161
+ class Numeric #:nodoc:
162
+ # No number is blank:
163
+ #
164
+ # 1.blank? # => false
165
+ # 0.blank? # => false
166
+ #
167
+ def blank?
168
+ false
169
+ end
170
+ end
171
+
172
+ class Symbol
173
+ def camelize
174
+ self.to_s.camelize
175
+ end
176
+ end
@@ -0,0 +1,66 @@
1
+ # taken lock, stock and 2 smoking barrels from rails / activesupport / lib / active_support / inflections.rb
2
+ # thanks again, rails team!
3
+
4
+ require_relative 'inflector/inflections'
5
+
6
+ module SyncwiseApi
7
+ Inflector.inflections do |inflect|
8
+ inflect.plural(/$/, 's')
9
+ inflect.plural(/s$/i, 's')
10
+ inflect.plural(/(ax|test)is$/i, '\1es')
11
+ inflect.plural(/(octop|vir)us$/i, '\1i')
12
+ inflect.plural(/(octop|vir)i$/i, '\1i')
13
+ inflect.plural(/(alias|status)$/i, '\1es')
14
+ inflect.plural(/(bu)s$/i, '\1ses')
15
+ inflect.plural(/(buffal|tomat)o$/i, '\1oes')
16
+ inflect.plural(/([ti])um$/i, '\1a')
17
+ inflect.plural(/([ti])a$/i, '\1a')
18
+ inflect.plural(/sis$/i, 'ses')
19
+ inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
20
+ inflect.plural(/(hive)$/i, '\1s')
21
+ inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
22
+ inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
23
+ inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
24
+ inflect.plural(/(m|l)ouse$/i, '\1ice')
25
+ inflect.plural(/(m|l)ice$/i, '\1ice')
26
+ inflect.plural(/^(ox)$/i, '\1en')
27
+ inflect.plural(/^(oxen)$/i, '\1')
28
+ inflect.plural(/(quiz)$/i, '\1zes')
29
+
30
+ inflect.singular(/s$/i, '')
31
+ inflect.singular(/(n)ews$/i, '\1ews')
32
+ inflect.singular(/([ti])a$/i, '\1um')
33
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
34
+ inflect.singular(/(^analy)ses$/i, '\1sis')
35
+ inflect.singular(/([^f])ves$/i, '\1fe')
36
+ inflect.singular(/(hive)s$/i, '\1')
37
+ inflect.singular(/(tive)s$/i, '\1')
38
+ inflect.singular(/([lr])ves$/i, '\1f')
39
+ inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
40
+ inflect.singular(/(s)eries$/i, '\1eries')
41
+ inflect.singular(/(m)ovies$/i, '\1ovie')
42
+ inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
43
+ inflect.singular(/(m|l)ice$/i, '\1ouse')
44
+ inflect.singular(/(bus)es$/i, '\1')
45
+ inflect.singular(/(o)es$/i, '\1')
46
+ inflect.singular(/(shoe)s$/i, '\1')
47
+ inflect.singular(/(cris|ax|test)es$/i, '\1is')
48
+ inflect.singular(/(octop|vir)i$/i, '\1us')
49
+ inflect.singular(/(alias|status)es$/i, '\1')
50
+ inflect.singular(/^(ox)en/i, '\1')
51
+ inflect.singular(/(vert|ind)ices$/i, '\1ex')
52
+ inflect.singular(/(matr)ices$/i, '\1ix')
53
+ inflect.singular(/(quiz)zes$/i, '\1')
54
+ inflect.singular(/(database)s$/i, '\1')
55
+
56
+ inflect.irregular('person', 'people')
57
+ inflect.irregular('man', 'men')
58
+ inflect.irregular('child', 'children')
59
+ inflect.irregular('sex', 'sexes')
60
+ inflect.irregular('move', 'moves')
61
+ inflect.irregular('cow', 'kine')
62
+ inflect.irregular('zombie', 'zombies')
63
+
64
+ inflect.uncountable(%w(equipment information rice money species series fish sheep jeans))
65
+ end
66
+ end
@@ -0,0 +1,177 @@
1
+ # taken lock, stock and 2 smoking barrels from rails / activesupport / lib / active_support / inflector / inflections.rb
2
+ # thanks again, rails team!
3
+
4
+ module SyncwiseApi
5
+ module Inflector
6
+ extend self
7
+
8
+ # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
9
+ # inflection rules. Examples:
10
+ #
11
+ # ActiveSupport::Inflector.inflections do |inflect|
12
+ # inflect.plural /^(ox)$/i, '\1\2en'
13
+ # inflect.singular /^(ox)en/i, '\1'
14
+ #
15
+ # inflect.irregular 'octopus', 'octopi'
16
+ #
17
+ # inflect.uncountable "equipment"
18
+ # end
19
+ #
20
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
21
+ # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
22
+ # already have been loaded.
23
+ class Inflections
24
+ def self.instance
25
+ @__instance__ ||= new
26
+ end
27
+
28
+ attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms, :acronym_regex
29
+
30
+ def initialize
31
+ @plurals, @singulars, @uncountables, @humans, @acronyms, @acronym_regex = [], [], [], [], {}, /(?=a)b/
32
+ end
33
+
34
+ # Specifies a new acronym. An acronym must be specified as it will appear in a camelized string. An underscore
35
+ # string that contains the acronym will retain the acronym when passed to `camelize`, `humanize`, or `titleize`.
36
+ # A camelized string that contains the acronym will maintain the acronym when titleized or humanized, and will
37
+ # convert the acronym into a non-delimited single lowercase word when passed to +underscore+.
38
+ #
39
+ # Examples:
40
+ # acronym 'HTML'
41
+ # titleize 'html' #=> 'HTML'
42
+ # camelize 'html' #=> 'HTML'
43
+ # underscore 'MyHTML' #=> 'my_html'
44
+ #
45
+ # The acronym, however, must occur as a delimited unit and not be part of another word for conversions to recognize it:
46
+ #
47
+ # acronym 'HTTP'
48
+ # camelize 'my_http_delimited' #=> 'MyHTTPDelimited'
49
+ # camelize 'https' #=> 'Https', not 'HTTPs'
50
+ # underscore 'HTTPS' #=> 'http_s', not 'https'
51
+ #
52
+ # acronym 'HTTPS'
53
+ # camelize 'https' #=> 'HTTPS'
54
+ # underscore 'HTTPS' #=> 'https'
55
+ #
56
+ # Note: Acronyms that are passed to `pluralize` will no longer be recognized, since the acronym will not occur as
57
+ # a delimited unit in the pluralized result. To work around this, you must specify the pluralized form as an
58
+ # acronym as well:
59
+ #
60
+ # acronym 'API'
61
+ # camelize(pluralize('api')) #=> 'Apis'
62
+ #
63
+ # acronym 'APIs'
64
+ # camelize(pluralize('api')) #=> 'APIs'
65
+ #
66
+ # `acronym` may be used to specify any word that contains an acronym or otherwise needs to maintain a non-standard
67
+ # capitalization. The only restriction is that the word must begin with a capital letter.
68
+ #
69
+ # Examples:
70
+ # acronym 'RESTful'
71
+ # underscore 'RESTful' #=> 'restful'
72
+ # underscore 'RESTfulController' #=> 'restful_controller'
73
+ # titleize 'RESTfulController' #=> 'RESTful Controller'
74
+ # camelize 'restful' #=> 'RESTful'
75
+ # camelize 'restful_controller' #=> 'RESTfulController'
76
+ #
77
+ # acronym 'McDonald'
78
+ # underscore 'McDonald' #=> 'mcdonald'
79
+ # camelize 'mcdonald' #=> 'McDonald'
80
+ def acronym(word)
81
+ @acronyms[word.downcase] = word
82
+ @acronym_regex = /#{@acronyms.values.join("|")}/
83
+ end
84
+
85
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
86
+ # The replacement should always be a string that may include references to the matched data from the rule.
87
+ def plural(rule, replacement)
88
+ @uncountables.delete(rule) if rule.is_a?(String)
89
+ @uncountables.delete(replacement)
90
+ @plurals.insert(0, [rule, replacement])
91
+ end
92
+
93
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
94
+ # The replacement should always be a string that may include references to the matched data from the rule.
95
+ def singular(rule, replacement)
96
+ @uncountables.delete(rule) if rule.is_a?(String)
97
+ @uncountables.delete(replacement)
98
+ @singulars.insert(0, [rule, replacement])
99
+ end
100
+
101
+ # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
102
+ # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
103
+ #
104
+ # Examples:
105
+ # irregular 'octopus', 'octopi'
106
+ # irregular 'person', 'people'
107
+ def irregular(singular, plural)
108
+ @uncountables.delete(singular)
109
+ @uncountables.delete(plural)
110
+ if singular[0,1].upcase == plural[0,1].upcase
111
+ plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
112
+ plural(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + plural[1..-1])
113
+ singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
114
+ else
115
+ plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
116
+ plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
117
+ plural(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
118
+ plural(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
119
+ singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
120
+ singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
121
+ end
122
+ end
123
+
124
+ # Add uncountable words that shouldn't be attempted inflected.
125
+ #
126
+ # Examples:
127
+ # uncountable "money"
128
+ # uncountable "money", "information"
129
+ # uncountable %w( money information rice )
130
+ def uncountable(*words)
131
+ (@uncountables << words).flatten!
132
+ end
133
+
134
+ # Specifies a humanized form of a string by a regular expression rule or by a string mapping.
135
+ # When using a regular expression based replacement, the normal humanize formatting is called after the replacement.
136
+ # When a string is used, the human form should be specified as desired (example: 'The name', not 'the_name')
137
+ #
138
+ # Examples:
139
+ # human /_cnt$/i, '\1_count'
140
+ # human "legacy_col_person_name", "Name"
141
+ def human(rule, replacement)
142
+ @humans.insert(0, [rule, replacement])
143
+ end
144
+
145
+ # Clears the loaded inflections within a given scope (default is <tt>:all</tt>).
146
+ # Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
147
+ # <tt>:singulars</tt>, <tt>:uncountables</tt>, <tt>:humans</tt>.
148
+ #
149
+ # Examples:
150
+ # clear :all
151
+ # clear :plurals
152
+ def clear(scope = :all)
153
+ case scope
154
+ when :all
155
+ @plurals, @singulars, @uncountables, @humans = [], [], [], []
156
+ else
157
+ instance_variable_set "@#{scope}", []
158
+ end
159
+ end
160
+ end
161
+
162
+ # Yields a singleton instance of Inflector::Inflections so you can specify additional
163
+ # inflector rules.
164
+ #
165
+ # Example:
166
+ # ActiveSupport::Inflector.inflections do |inflect|
167
+ # inflect.uncountable "rails"
168
+ # end
169
+ def inflections
170
+ if block_given?
171
+ yield Inflections.instance
172
+ else
173
+ Inflections.instance
174
+ end
175
+ end
176
+ end
177
+ end