formatting 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0eedbb12f830e0efcd539953a2161c5e56b521fe
4
+ data.tar.gz: 27a038999934b49bce503907e1aec13307729c56
5
+ SHA512:
6
+ metadata.gz: ee6f14dcfc48e9ad749c57e86fb221227bda44312ae1dbc20072bbd58d4afec0e1ec8f22a567ff98671133dfbf6da642b08b6021523f11423067a4fc03356cd9
7
+ data.tar.gz: 1228b163c277ee2d7f85e833fa9c92c975876e56e9a8f4dbb7d1bf395eb62d7d09d88a57376544710141c9e94928f0088b93e1b80f294d331e9ecaf6d4d29b07
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in formatting.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Barsoom AB
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,85 @@
1
+ # Formatting
2
+
3
+ Rails-less formatting for your unit-testable code.
4
+
5
+ *Does* currently depend on the `i18n` library for number separators.
6
+
7
+ Very much a work in progress currently.
8
+
9
+ Formats:
10
+ * Numbers
11
+ * Currency
12
+
13
+
14
+ ## Usage
15
+
16
+ Call methods on `Formatting`:
17
+
18
+ ``` ruby
19
+ Formatting.format_number(1234.567) # => "1,234.57"
20
+ ```
21
+
22
+ Or include the modules you want:
23
+
24
+ ``` ruby
25
+ include Formatting::Number
26
+ format_number(1234) # => "1,234"
27
+
28
+ include Formatting::Currency
29
+ format_currency("SEK", 1234) # => "1,234 SEK"
30
+ ```
31
+
32
+
33
+ ### Number
34
+
35
+ ``` ruby
36
+ Formatting.format_number(1234.567) # => "1,234.57"
37
+ Formatting.format_number(0, blank_when_zero: true) # => ""
38
+ Formatting.format_number(1, explicit_sign: true) # => "+1"
39
+ ```
40
+
41
+ ### Currency
42
+
43
+ The currency formatter should usually be passed some object that
44
+ the currency can be determined from. The idea is that even if you
45
+ only have one currency now, you may add more later.
46
+
47
+ ``` ruby
48
+ Formatting.format_currency("SEK", 1234) # => "1,234 SEK"
49
+
50
+ item = Item.new(price: 1234, currency: "SEK")
51
+ Formatting.format_currency(item, :price) # => "1,234 SEK"
52
+ Formatting.format_currency(company, item.price) # => "1,234 SEK"
53
+
54
+ Formatting.defaults[:currency] = "SEK"
55
+ item = Item.new(price: 1234) # Does not respond to "currency"
56
+ Formatting.format_currency(item, :price) # => "1,234 SEK"
57
+
58
+ item = Item.new(price: 1234, currency: "SEK")
59
+ Formatting.format_currency(item, :price, show_currency: false) # => "1,234"
60
+ Formatting.defaults[:show_currency] = false
61
+ Formatting.format_currency(item, :price) # => "1,234"
62
+ ```
63
+
64
+
65
+ ## Installation
66
+
67
+ Add this line to your application's Gemfile:
68
+
69
+ gem 'formatting'
70
+
71
+ And then execute:
72
+
73
+ $ bundle
74
+
75
+ Or install it yourself as:
76
+
77
+ $ gem install formatting
78
+
79
+
80
+ ## TODO
81
+
82
+ * Actually use i18n for separators
83
+ * Don't depend on `i18n`?
84
+ * Rename? This name is boring and also generic enough that collisions seem likely.
85
+ * Document options
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'formatting/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "formatting"
8
+ spec.version = Formatting::VERSION
9
+ spec.authors = ["Henrik Nyh"]
10
+ spec.email = ["henrik@nyh.se"]
11
+ spec.summary = %q{Rails-less formatting for your unit-testable code.}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "i18n"
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "rspec"
25
+ end
@@ -0,0 +1,35 @@
1
+ module Formatting
2
+ module Currency
3
+ include Number
4
+
5
+ def format_currency(record, amount_or_method, opts = {})
6
+ opts = Formatting.defaults.merge(opts)
7
+
8
+ format_string = opts.fetch(:format, "<amount> <currency>")
9
+
10
+ currency = opts.fetch(:currency) {
11
+ record.respond_to?(:currency) ? record.currency: nil
12
+ }
13
+
14
+ if amount_or_method.is_a?(Symbol)
15
+ amount = record.public_send(amount_or_method)
16
+ else
17
+ amount = amount_or_method
18
+ end
19
+
20
+ amount = format_number(amount, opts)
21
+ apply_format_string(format_string, amount, currency)
22
+ end
23
+
24
+ private
25
+
26
+ def apply_format_string(format_string, amount, currency)
27
+ out = format_string.dup
28
+ out.gsub!("<amount>", amount)
29
+ out.gsub!("<currency>", currency.to_s)
30
+ out.strip!
31
+ out.gsub!(" ", NON_BREAKING_SPACE)
32
+ out
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ module Formatting
2
+ module Number
3
+ def format_number(number, opts = {})
4
+ opts = Formatting.defaults.merge(opts)
5
+
6
+ thousands_separator = opts.fetch(:thousands_separator, NON_BREAKING_SPACE)
7
+ decimal_separator = opts.fetch(:decimal_separator, ".")
8
+ round = opts.fetch(:round, nil)
9
+ min_decimals = opts.fetch(:min_decimals, nil)
10
+ explicit_sign = opts.fetch(:explicit_sign, false)
11
+ blank_when_zero = opts.fetch(:blank_when_zero, false)
12
+
13
+ if blank_when_zero
14
+ return "" if number.zero?
15
+ end
16
+
17
+ # Avoid negative zero.
18
+ number = 0 if number.zero?
19
+
20
+ if round
21
+ number = number.round(round)
22
+ end
23
+
24
+ integer, decimals = number.to_s.split(".")
25
+ decimals ||= "0"
26
+
27
+ integer.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{thousands_separator}")
28
+
29
+ if explicit_sign
30
+ integer = "+#{integer}" if number > 0
31
+ end
32
+
33
+ if min_decimals
34
+ decimals = decimals.ljust(min_decimals, "0")
35
+ end
36
+
37
+ [integer, decimals].join(decimal_separator)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module Formatting
2
+ VERSION = "0.0.1"
3
+ end
data/lib/formatting.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "formatting/version"
2
+ require "formatting/number"
3
+ require "formatting/currency"
4
+
5
+ module Formatting
6
+ NON_BREAKING_SPACE = "\xc2\xa0"
7
+
8
+ class << self
9
+ attr_accessor :defaults
10
+ end
11
+
12
+ self.defaults = {}
13
+
14
+ extend Number
15
+ extend Currency
16
+ end
@@ -0,0 +1,83 @@
1
+ require "spec_helper"
2
+
3
+ describe Formatting::Currency do
4
+ it "can be included as a module" do
5
+ object = Object.new
6
+ object.extend Formatting::Currency
7
+ expect(object).to respond_to(:format_currency)
8
+ end
9
+ end
10
+
11
+ describe Formatting do
12
+ describe ".format_currency" do
13
+ let(:item) { double }
14
+
15
+ context "method signature" do
16
+ it "can take a record and a value" do
17
+ expect_formatted(item, 1).to eq space_to_nbsp("1.0")
18
+ end
19
+
20
+ it "can take a record and a method name" do
21
+ item.stub(price: 2)
22
+ expect_formatted(item, :price).to eq space_to_nbsp("2.0")
23
+ end
24
+ end
25
+
26
+ context "formatting" do
27
+ it "formats numbers" do
28
+ expect_formatted(item, 1234.56).to include space_to_nbsp("1 234.56")
29
+ end
30
+
31
+ it "passes on number formatting options" do
32
+ expect_formatted(item, 1.567, round: 2).to include "1.57"
33
+ end
34
+
35
+ it "applies default options" do
36
+ Formatting.defaults = { currency: "FOO" }
37
+ expect_formatted(item, 1).to eq space_to_nbsp("1.0 FOO")
38
+ end
39
+ end
40
+
41
+ context "currency option" do
42
+ it "is added if provided" do
43
+ expect_formatted(item, 1234.56, currency: "XYZ").to eq space_to_nbsp("1 234.56 XYZ")
44
+ end
45
+
46
+ it "is read from the record's #currency if present" do
47
+ item.stub(currency: "SEK")
48
+ expect_formatted(item, 1).to eq space_to_nbsp("1.0 SEK")
49
+ end
50
+
51
+ it "is not added if the record's #currency is blank" do
52
+ item.stub(currency: "")
53
+ expect_formatted(item, 1).to eq space_to_nbsp("1.0")
54
+ end
55
+
56
+ it "is not added if the record does not respond to #currency" do
57
+ expect_formatted(item, 1).to eq space_to_nbsp("1.0")
58
+ end
59
+ end
60
+
61
+ context "format string option" do
62
+ it "is used if provided" do
63
+ expect_formatted(item, 123, format: "C: <currency> A: <amount>", currency: "XYZ").
64
+ to eq space_to_nbsp("C: XYZ A: 123.0")
65
+ end
66
+
67
+ it "will have spaces turned into non-breaking spaces" do
68
+ expect_actual = expect_formatted(item, 123, format: "<amount> <currency>", currency: "XYZ")
69
+ expect_actual.to eq space_to_nbsp("123.0 XYZ")
70
+ expect_actual.not_to eq "123.0 XYZ"
71
+ end
72
+
73
+ it "is stripped" do
74
+ expect_formatted(item, 123, format: "<amount> <currency>", currency: nil).
75
+ to eq space_to_nbsp("123.0")
76
+ end
77
+ end
78
+ end
79
+
80
+ def expect_formatted(record, value, opts = {})
81
+ expect(Formatting.format_currency(record, value, opts))
82
+ end
83
+ end
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+
3
+ describe Formatting do
4
+ describe "defaults" do
5
+ it "starts out as an empty hash" do
6
+ expect(Formatting.defaults).to eq({})
7
+ end
8
+
9
+ it "can get and set them" do
10
+ Formatting.defaults = { hello: "world" }
11
+ expect(Formatting.defaults).to eq({ hello: "world" })
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,76 @@
1
+ require "spec_helper"
2
+
3
+ describe Formatting::Number do
4
+ it "can be included as a module" do
5
+ object = Object.new
6
+ object.extend Formatting::Number
7
+ expect(object).to respond_to(:format_number)
8
+ end
9
+ end
10
+
11
+ describe Formatting do
12
+ describe ".format_number" do
13
+ it "groups thousands" do
14
+ expect_formatted(1234567.89).to eq space_to_nbsp("1 234 567.89")
15
+ end
16
+
17
+ it "applies default options" do
18
+ Formatting.defaults = { round: 3 }
19
+ expect_formatted(12.3456789).to eq "12.346"
20
+ end
21
+
22
+ context "rounding" do
23
+ it "doesn't round by default" do
24
+ expect_formatted(12.3456789).to eq "12.3456789"
25
+ end
26
+
27
+ it "rounds to the given number of decimals" do
28
+ expect_formatted(12.3456789, round: 2).to eq "12.35"
29
+ end
30
+ end
31
+
32
+ context "blanking when zero" do
33
+ it "does not happen by default" do
34
+ expect_formatted(0).to eq "0.0"
35
+ end
36
+
37
+ it "can be enforced" do
38
+ expect_formatted(0, blank_when_zero: true).to eq ""
39
+ end
40
+ end
41
+
42
+
43
+ context "minimum number of decimals" do
44
+ it "is not enforced by default" do
45
+ expect_formatted(12).to eq "12.0"
46
+ expect_formatted(12.3).to eq "12.3"
47
+ end
48
+
49
+ it "can be enforced" do
50
+ expect_formatted(12.3, min_decimals: 2).to eq "12.30"
51
+ end
52
+ end
53
+
54
+ context "explicit sign" do
55
+ it "is not included by default" do
56
+ expect_formatted(1).to eq "1.0"
57
+ expect_formatted(0).to eq "0.0"
58
+ expect_formatted(-1).to eq "-1.0"
59
+ end
60
+
61
+ it "never shows 0 as negative" do
62
+ expect_formatted(-0.0).to eq "0.0"
63
+ end
64
+
65
+ it "can be enforced" do
66
+ expect_formatted(1, explicit_sign: true).to eq "+1.0"
67
+ expect_formatted(0, explicit_sign: true).to eq "0.0"
68
+ expect_formatted(-1, explicit_sign: true).to eq "-1.0"
69
+ end
70
+ end
71
+ end
72
+
73
+ def expect_formatted(value, opts = {})
74
+ expect(Formatting.format_number(value, opts))
75
+ end
76
+ end
@@ -0,0 +1,15 @@
1
+ require "formatting"
2
+
3
+ module Helpers
4
+ def space_to_nbsp(value)
5
+ value.gsub(" ", "\xc2\xa0")
6
+ end
7
+ end
8
+
9
+ RSpec.configure do |config|
10
+ config.include Helpers
11
+
12
+ config.before do
13
+ Formatting.defaults = {}
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: formatting
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Henrik Nyh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: i18n
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - henrik@nyh.se
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - formatting.gemspec
82
+ - lib/formatting.rb
83
+ - lib/formatting/currency.rb
84
+ - lib/formatting/number.rb
85
+ - lib/formatting/version.rb
86
+ - spec/currency_spec.rb
87
+ - spec/formatting_spec.rb
88
+ - spec/number_spec.rb
89
+ - spec/spec_helper.rb
90
+ homepage: ''
91
+ licenses:
92
+ - MIT
93
+ metadata: {}
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubyforge_project:
110
+ rubygems_version: 2.0.3
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: Rails-less formatting for your unit-testable code.
114
+ test_files:
115
+ - spec/currency_spec.rb
116
+ - spec/formatting_spec.rb
117
+ - spec/number_spec.rb
118
+ - spec/spec_helper.rb
119
+ has_rdoc: