celsius 0.2.0 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2a521e978a4541083a2873c57a94f08ea02c1e79
4
- data.tar.gz: 22df803f547fc9accbca5da2d7ca60ddcafb8759
3
+ metadata.gz: 347a4f4d7898e806d74c07e71f0c0f303ac52d5f
4
+ data.tar.gz: 0757d90d257529ef4005b5edea762707e5b09d1c
5
5
  SHA512:
6
- metadata.gz: 9f1c01cbd35521cfc11aaf768179b57f0429890f7c9d544a4fdfcb062c4550a5b8adff30e61dd398e535e71628dc78116536f8c0cfc9596bef34d22e28350484
7
- data.tar.gz: d5c9392cbf1e18db04749e762454f37408c07bf88fb7ba40edea704245f035af28490d8adf1702401bbdbcd59d809a5d460a6fad445ddd1dadf240724082b3d5
6
+ metadata.gz: 6d119c40a39c4cd69bf00e8bb286580e623adf72fd40185612282d00fd1d9f7aad1335bd11a3ea1a4d77a199627625b2df072c252fd47a99bdfe6c253a2e79f7
7
+ data.tar.gz: 15dd8d70fdf9bfb6c2953a373ad6c5908426ae520135a66821c4c2f4496ec023156102e59c8e459f665144d587805af000dbba5c4973825194ca04cfa4281fc7
data/Gemfile CHANGED
@@ -7,3 +7,5 @@ gem "pry", "~> 0.9.12.6"
7
7
  gem "pry-nav", "~> 0.2.3"
8
8
  gem "pry-stack_explorer", "~> 0.4.9.1"
9
9
  gem "pry-syntax-hacks", "~> 0.0.6"
10
+
11
+ gem "deep_merger", path: "~/github/ubpb/deep_merger"
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Celsius
1
+ # Celsius [![Code Climate](https://codeclimate.com/github/ubpb/celsius/badges/gpa.svg)](https://codeclimate.com/github/ubpb/celsius)
2
2
 
3
3
  TODO: Write a gem description
4
4
 
data/celsius.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_dependency "deep_merger", ">= 0.0.2"
20
+ spec.add_dependency "deep_merger", ">= 0.1.0"
21
21
 
22
22
  spec.add_development_dependency "bundler", ">= 1.5"
23
23
  spec.add_development_dependency "rspec", ">= 3.0.0", "< 4.0.0"
@@ -1,2 +1,10 @@
1
+ require "celsius"
2
+ require "celsius/i18n"
3
+
1
4
  class Celsius::Adapter
5
+ include Celsius::I18n
6
+
7
+ def initialize(*args)
8
+ self.class.load_locales_from_directory("#{File.dirname(__FILE__)}/locales")
9
+ end
2
10
  end
@@ -0,0 +1,34 @@
1
+ require "celsius"
2
+
3
+ module Celsius::Hash
4
+ #
5
+ # This module provides some helper functions for dealing with hashes
6
+ #
7
+ def self.deep_find_key(object, key)
8
+ results = []
9
+
10
+ if key.is_a?(Array)
11
+ key.inject(object) do |memo, key_element|
12
+ deep_find_key(memo, key_element)
13
+ end
14
+ else
15
+ if object.is_a?(Array)
16
+ # flatten(1) prevents unintend array nesting due to recursion
17
+ results.concat object.map { |value| deep_find_key(value, key) }.flatten(1)
18
+ elsif object.is_a?(Hash)
19
+ if object.has_key?(key.to_s) || object.has_key?(key.to_sym)
20
+ results << (object[key.to_s] || object[key.to_sym])
21
+ else
22
+ # its easier to concat an empty array than checking for nil
23
+ results.concat deep_find_key(object.values, key) || []
24
+ end
25
+ end
26
+
27
+ # remove nils
28
+ results.compact!
29
+
30
+ # in case nothing was found, return nil to ease detecting this case
31
+ results.empty? ? nil : results
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ require "deep_merger"
2
+ require "yaml"
3
+
4
+ module Celsius::I18n
5
+ def self.included(klass)
6
+ unless klass.class_variable_defined?(:@@locales)
7
+ klass.class_variable_set(:@@locales, {})
8
+ end
9
+
10
+ klass.extend(ClassMethods)
11
+ end
12
+
13
+ module ClassMethods
14
+ def load_locales_from_directory(path)
15
+ # class_variable_get is needed to avoid implicite referencing the module instead of the including class
16
+ Dir.glob("#{File.expand_path(path)}/*.yml").inject(self.class_variable_get(:@@locales)) do |locales, filename|
17
+ DeepMerger.deep_merge!(locales, YAML.load_file(filename))
18
+ end
19
+ end
20
+ end
21
+
22
+ def translate(key, options = {})
23
+ raise "Destination locale missing!" if options[:locale].nil?
24
+
25
+ fully_qualified_key = "#{options[:locale]}.#{key}"
26
+ keys_path = fully_qualified_key.split(".")
27
+ locales = self.class.class_variable_get(:@@locales)
28
+
29
+ keys_path.inject(locales) do |hash, hash_key|
30
+ unless hash.nil?
31
+ hash[hash_key.to_s] || hash[hash_key.to_sym]
32
+ end
33
+ end || keys_path.last
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ de:
2
+ field_names:
3
+ _all: Alle Felder
4
+ _score: Relevanz
5
+ created: Erscheinungsjahr
6
+ creator: Autor/Herausgeber
7
+ identifier: Identifikator
8
+ subject: Schlagwort
9
+ title: Titel
@@ -0,0 +1,9 @@
1
+ en:
2
+ field_names:
3
+ _all: All fields
4
+ _score: Score
5
+ created: Created
6
+ creator: Creator
7
+ identifier: Identifier
8
+ subject: Subject
9
+ title: Title
@@ -0,0 +1,22 @@
1
+ class Celsius::Transformation::Step
2
+ attr_accessor :transformation
3
+
4
+ def initialize(transformation)
5
+ @transformation = transformation
6
+ end
7
+
8
+ #
9
+ # Each step has transparent access to all methods of it's transformation
10
+ #
11
+ def method_missing(method_name, *args, &block)
12
+ if @transformation.respond_to?(method_name)
13
+ @transformation.send(method_name, *args, &block)
14
+ else
15
+ super
16
+ end
17
+ end
18
+
19
+ def respond_to_missing?(method_name, include_private = false)
20
+ @transformation.respond_to?(method_name) || super
21
+ end
22
+ end
@@ -0,0 +1,46 @@
1
+ require "celsius"
2
+
3
+ class Celsius::Transformation
4
+ #
5
+ # class methods
6
+ #
7
+ class << self
8
+ attr_accessor :steps
9
+ end
10
+
11
+ # since a transformation can have many steps, writing a "require" for each is tedious
12
+ def self.require_directory(directory)
13
+ Dir.glob("#{File.expand_path(directory)}/*.rb").each do |filename|
14
+ require filename
15
+ end
16
+ end
17
+
18
+ # convenience wrapper for @steps setter to enhance readability
19
+ def self.sequence(value)
20
+ self.steps = value
21
+ end
22
+
23
+ #
24
+ # instance methods
25
+ #
26
+ attr_accessor :source
27
+ attr_accessor :target
28
+
29
+ def apply(options = {})
30
+ if (@source = options[:source] ||= options[:to]).nil?
31
+ raise ArgumentError, "No source given to apply transformation to!"
32
+ end
33
+
34
+ @target = options[:target]
35
+
36
+ self.class.steps.flatten.each do |step|
37
+ if step.is_a?(Class)
38
+ step.new(self).call
39
+ else
40
+ step.call(self)
41
+ end
42
+ end
43
+
44
+ return @target
45
+ end
46
+ end
@@ -1,3 +1,3 @@
1
1
  module Celsius
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/celsius.rb CHANGED
@@ -1,38 +1,9 @@
1
1
  require "celsius/version"
2
- require "deep_merger"
3
2
 
4
3
  module Celsius
5
4
  require "celsius/adapter"
6
-
7
- def self.deep_clone(object)
8
- Marshal.load(Marshal.dump(object))
9
- end
10
-
11
- def self.deep_merge!(destination, source, options = {})
12
- DeepMerger.deep_merge!(source, destination, options)
13
- end
14
-
15
- def self.deep_stringify_keys(hash)
16
- Celsius.deep_stringify_keys!(Celsius.deep_clone(hash))
17
- end
18
-
19
- #
20
- private
21
- #
22
-
23
- # http://stackoverflow.com/questions/8379596/how-do-i-convert-a-ruby-hash-so-that-all-of-its-keys-are-symbols
24
- def self.deep_stringify_keys!(hash_or_element)
25
- case hash_or_element
26
- when Hash
27
- Hash[
28
- hash_or_element.map do |key, value|
29
- [ key.respond_to?(:to_s) ? key.to_s : key, deep_stringify_keys(value) ]
30
- end
31
- ]
32
- when Enumerable
33
- hash_or_element.map { |value| deep_stringify_keys(value) }
34
- else
35
- hash_or_element
36
- end
37
- end
5
+ require "celsius/hash"
6
+ require "celsius/i18n"
7
+ require "celsius/transformation"
8
+ require "celsius/transformation/step"
38
9
  end
@@ -0,0 +1,9 @@
1
+ de:
2
+ field_names:
3
+ _all: Alle Felder
4
+ _score: Relevanz
5
+ created: Erscheinungsjahr
6
+ creator: Autor/Herausgeber
7
+ identifier: Identifikator
8
+ subject: Schlagwort
9
+ title: Titel
@@ -0,0 +1,9 @@
1
+ en:
2
+ field_names:
3
+ _all: All fields
4
+ _score: Score
5
+ created: Created
6
+ creator: Creator
7
+ identifier: Identifier
8
+ subject: Subject
9
+ title: Title
@@ -0,0 +1,2 @@
1
+ class SomeClass
2
+ end
@@ -0,0 +1,28 @@
1
+ describe Celsius::Adapter do
2
+ let(:adapter) { described_class.new() }
3
+
4
+ context "when a class is derived from #{described_class}" do
5
+ context "when the derived class overwrites .initialize" do
6
+ context "when the derived class calls super inside the overwritten .initalize" do
7
+ let(:derived_class) do
8
+ Class.new(described_class) do
9
+ def initialize
10
+ super
11
+ end
12
+ end
13
+ end
14
+
15
+ let(:derived_class_instance) do
16
+ derived_class.new
17
+ end
18
+
19
+ it "has access to the superclass locales" do
20
+ translation_key_known_by_superclass = "field_names.creator"
21
+ translation = derived_class_instance.translate(translation_key_known_by_superclass, locale: :de)
22
+ expected_translation = derived_class_instance.class.class_variable_get(:@@locales)["de"]["field_names"]["creator"]
23
+ expect(translation).to eq(expected_translation)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,60 @@
1
+ require "celsius/hash"
2
+
3
+ describe Celsius::Hash do
4
+ describe ".deep_find_key" do
5
+ let(:hash) do
6
+ {
7
+ query: {
8
+ bool: [
9
+ {
10
+ query_string: {
11
+ query: "a"
12
+ }
13
+ },
14
+ {
15
+ query_string: {
16
+ query: "b"
17
+ }
18
+ },
19
+ {
20
+ match: {
21
+ some_field: "some_value"
22
+ }
23
+ }
24
+ ]
25
+ },
26
+ facets: {
27
+ creator: {
28
+ terms: {
29
+ field: "facet_creator"
30
+ }
31
+ },
32
+ lang: {
33
+ terms: {
34
+ field: "facet_lang",
35
+ }
36
+ }
37
+ }
38
+ }
39
+ end
40
+
41
+ it "returns values matching the given key" do
42
+ expected_result = [
43
+ hash[:query][:bool][0][:query_string],
44
+ hash[:query][:bool][1][:query_string],
45
+ ]
46
+
47
+ expect(described_class.deep_find_key(hash, :query_string)).to eq(expected_result)
48
+ end
49
+
50
+ context "if given an array of keys" do
51
+ it "tries to find each element based on the former elements result" do
52
+ expected_result = [
53
+ hash[:facets][:creator]
54
+ ]
55
+
56
+ expect(described_class.deep_find_key(hash, [:facets, :creator])).to eq(expected_result)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,86 @@
1
+ require "celsius/i18n"
2
+
3
+ describe Celsius::I18n do
4
+ let(:class_with_i18n_included) do
5
+ Class.new.tap do |klass|
6
+ klass.include(Celsius::I18n)
7
+ end
8
+ end
9
+
10
+ context "when included into a class" do
11
+ context "when the including class has a class variable named @@locales" do
12
+ let(:value_of_locales) do
13
+ { foo: "bar" }
14
+ end
15
+
16
+ let(:klass) do
17
+ Class.new.tap do |_klass|
18
+ _klass.class_variable_set(:@@locales, value_of_locales)
19
+ _klass.include(Celsius::I18n)
20
+ end
21
+ end
22
+
23
+ it "does not alter the existing class variable" do
24
+ expect(klass.class_variable_get(:@@locales)).to eq(value_of_locales)
25
+ end
26
+ end
27
+
28
+ context "when the including class has no class variable named @@locales" do
29
+ let(:klass) do
30
+ Class.new.tap do |_klass|
31
+ _klass.include(Celsius::I18n)
32
+ end
33
+ end
34
+
35
+ it "defines a class variable named @@locales as an empty hash" do
36
+ expect(klass.class_variable_get(:@@locales)).to eq({})
37
+ end
38
+ end
39
+
40
+ it "defines a class method #load_locales_from_directory" do
41
+ expect(class_with_i18n_included).to respond_to(:load_locales_from_directory)
42
+ end
43
+
44
+ it "defines an instance method .translate" do
45
+ expect(class_with_i18n_included.new).to respond_to(:translate)
46
+ end
47
+ end
48
+
49
+ describe "#load_locales_from_directory" do
50
+ it "loads all yaml encoded locales from a directory and adds them to @@locales" do
51
+ class_with_i18n_included.load_locales_from_directory(File.expand_path("#{File.dirname(__FILE__)}/../assets/locales"))
52
+ expect(class_with_i18n_included.class_variable_get(:@@locales)).not_to be_empty
53
+ end
54
+ end
55
+
56
+ describe "#translate" do
57
+ let(:object) do
58
+ class_with_i18n_included.new.tap do |object|
59
+ object.class.load_locales_from_directory(File.expand_path("#{File.dirname(__FILE__)}/../assets/locales"))
60
+ end
61
+ end
62
+
63
+ it "translates the given key into the language specified by the locale option" do
64
+ translated_key_de = object.translate("field_names.creator", locale: :de)
65
+ translated_key_en = object.translate("field_names.creator", locale: :en)
66
+
67
+ expected_translation_de = object.class.class_variable_get(:@@locales)["de"]["field_names"]["creator"]
68
+ expected_translation_en = object.class.class_variable_get(:@@locales)["en"]["field_names"]["creator"]
69
+
70
+ expect(translated_key_de).to eq(expected_translation_de)
71
+ expect(translated_key_en).to eq(expected_translation_en)
72
+ end
73
+
74
+ context "when there is no translation" do
75
+ it "returns to last key path" do
76
+ expect(object.translate("foo.bar.muff", locale: :en)).to eq("muff")
77
+ end
78
+ end
79
+
80
+ context "when no locale option is given" do
81
+ it "raises an exception" do
82
+ expect { object.translate("field_names.creator") }.to raise_error
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,36 @@
1
+ describe Celsius::Transformation::Step do
2
+ context "when initialized with a transformation" do
3
+ let(:transformation) do
4
+ Class.new(Celsius::Transformation) do
5
+ def some_transformation_method
6
+ true
7
+ end
8
+ end.new
9
+ end
10
+
11
+ let(:step) do
12
+ described_class.new(transformation)
13
+ end
14
+
15
+ describe "#transformation" do
16
+ it "allows access to the transformation" do
17
+ expect(step.transformation).to be(transformation)
18
+ end
19
+ end
20
+
21
+ context "if a unknown method is called" do
22
+ context "if the transformation has a matching method" do
23
+ it "calls the method on the transformation" do
24
+ expect(step).to respond_to(:some_transformation_method)
25
+ expect(step.some_transformation_method).to eq(transformation.some_transformation_method)
26
+ end
27
+ end
28
+
29
+ context "if the transformation has no matching method" do
30
+ it "raises an error" do
31
+ expect { step.some_unknown_method }.to raise_error
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,60 @@
1
+ describe Celsius::Transformation do
2
+ describe ".require_directory" do
3
+ it "requires all *.rb files in the given directory" do
4
+ described_class.require_directory "#{File.dirname(__FILE__)}/../assets/transformation"
5
+ expect(defined?(SomeClass)).to eq("constant")
6
+ end
7
+ end
8
+
9
+ describe "#sequence" do
10
+ let(:steps_array) do
11
+ [ -> { } ]
12
+ end
13
+
14
+ let(:transformation) do
15
+ steps = steps_array
16
+
17
+ Class.new(described_class) do
18
+ sequence steps
19
+ end
20
+ end
21
+
22
+ it "is a wrapper for the steps setter" do
23
+ expect(transformation.steps).to be(steps_array)
24
+ end
25
+ end
26
+
27
+ describe "#apply" do
28
+ let(:transformation) do
29
+ step_class = Class.new(described_class::Step) do
30
+ def call
31
+ transformation.target = source.dup
32
+ end
33
+ end
34
+
35
+ step_lambda = -> (transformation) do
36
+ transformation.target.upcase!
37
+ end
38
+
39
+ Class.new(described_class) do
40
+ sequence [
41
+ step_class,
42
+ step_lambda
43
+ ]
44
+ end.new
45
+ end
46
+
47
+ context "if no :source or :to option is given" do
48
+ it "raises an error" do
49
+ expect { transformation.apply }.to raise_error(ArgumentError)
50
+ end
51
+ end
52
+
53
+ it "applies the transformation" do
54
+ some_string = "foo"
55
+
56
+ expect(transformation.apply(to: some_string)).to eq(some_string.upcase)
57
+ expect(some_string).to eq("foo")
58
+ end
59
+ end
60
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: celsius
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Sievers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-06 00:00:00.000000000 Z
11
+ date: 2015-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deep_merger
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.2
19
+ version: 0.1.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.0.2
26
+ version: 0.1.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -101,7 +101,21 @@ files:
101
101
  - celsius.gemspec
102
102
  - lib/celsius.rb
103
103
  - lib/celsius/adapter.rb
104
+ - lib/celsius/hash.rb
105
+ - lib/celsius/i18n.rb
106
+ - lib/celsius/locales/de.yml
107
+ - lib/celsius/locales/en.yml
108
+ - lib/celsius/transformation.rb
109
+ - lib/celsius/transformation/step.rb
104
110
  - lib/celsius/version.rb
111
+ - spec/assets/locales/de.yml
112
+ - spec/assets/locales/en.yml
113
+ - spec/assets/transformation/some_class.rb
114
+ - spec/celsius/adapter_spec.rb
115
+ - spec/celsius/hash_spec.rb
116
+ - spec/celsius/i18n_spec.rb
117
+ - spec/celsius/transformation/step_spec.rb
118
+ - spec/celsius/transformation_spec.rb
105
119
  - spec/celsius_spec.rb
106
120
  - spec/spec_helper.rb
107
121
  homepage: http://github.com/ubpb/celsius
@@ -124,10 +138,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
138
  version: '0'
125
139
  requirements: []
126
140
  rubyforge_project:
127
- rubygems_version: 2.4.1
141
+ rubygems_version: 2.4.5
128
142
  signing_key:
129
143
  specification_version: 4
130
- summary: celsius-0.2.0
144
+ summary: celsius-0.4.0
131
145
  test_files:
146
+ - spec/assets/locales/de.yml
147
+ - spec/assets/locales/en.yml
148
+ - spec/assets/transformation/some_class.rb
149
+ - spec/celsius/adapter_spec.rb
150
+ - spec/celsius/hash_spec.rb
151
+ - spec/celsius/i18n_spec.rb
152
+ - spec/celsius/transformation/step_spec.rb
153
+ - spec/celsius/transformation_spec.rb
132
154
  - spec/celsius_spec.rb
133
155
  - spec/spec_helper.rb