celsius 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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