massager 0.1.1 → 0.2.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: 0de927f4b6c1c57de9734a7f173c9c2429f29fee
4
- data.tar.gz: b76f29ffbd8e782c8a00a28f38c5001be83f6ef1
3
+ metadata.gz: 53f2c10f9317523283972f8951006e762166f9c9
4
+ data.tar.gz: ce31aa5c501efde93d6b7fa5ad2787690e502689
5
5
  SHA512:
6
- metadata.gz: 3a444f625b9641cc69b4c944c9170164ea28e1e8aec0967237db696bd9cbfa278cf1ec7fcf0fe345346cf6d3db3fec5a49d36ba28fcb2ac28c9c7138b97b1ed2
7
- data.tar.gz: a56754ed98e5b0861beccd7ef7e45c38727c5697cdb7466a5fcf1a6f0d46b25139e499d391d956bf717607aa88b5724129f557cd73ecdaf178e525f5974acd69
6
+ metadata.gz: 738f93609dbd29d766e922f239d2da48aab11404b449e7a0041263f8f3af7dd493c83acb3120e7a208c134ad9627d3244d9f793dbf89316cc44b6ea7cad9aa6d
7
+ data.tar.gz: b5e655c41a1a8623a006c4f09190508a22e648c2ce79f7b29f26a2af6fa21206562d26db128042faa8ea5f1e785492a42eb33dedfc7da0ddfcf90d42e6d28ba1
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Massager
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/massager`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ Have you ever felt a need to massage your data just a little bit before working with it? This is what Massager was built for.
6
4
 
7
5
  ## Installation
8
6
 
@@ -20,20 +18,114 @@ Or install it yourself as:
20
18
 
21
19
  $ gem install massager
22
20
 
23
- ## Usage
21
+ ## Simplest usecase
22
+ To start using Massager, just include it in your classes, like so:
23
+ ```ruby
24
+ class ExampleClass
25
+ include Massager
26
+ attribute :foo, "bar"
27
+ end
28
+ ```
29
+ In this scenario, the "bar" key's value will become the result `foo` method
30
+ ```ruby
31
+ testable = ExampleClass.build({"bar" => "value"})
32
+ testable.foo #=> "value"
33
+ ```
34
+
35
+ ## Type checking
36
+ You can also pass type checks using dry-types library:
37
+ ```ruby
38
+ class ExampleClass
39
+ include Massager
40
+ attribute :foo, "bar", type: Types::Strict::String
41
+ end
42
+ ```
43
+ It will raise an error if the type is not correct:
44
+ ```ruby
45
+ testable = ExampleClass.build({"bar" => "value"})
46
+ testable.foo #=> "value"
47
+ testable = ExampleClass.build({"bar" => 123})
48
+ testable.foo #=> raises Dry::Types::ConstraintError
49
+ ```
50
+ If you want to define your own types, check the Dry Types library. Type needs to respond to `call` method, so
51
+ you can define your own
52
+
53
+ ## Preprocessing the value via block
54
+
55
+ You can add bit of preprocessing via block (The type check will be preformed afer the block is executed):
56
+ ```ruby
57
+ class ExampleClass
58
+ include Massager
59
+ attribute :foo, "bar", type: Types::Strict::String do |v|
60
+ v.upcase
61
+ end
62
+ end
63
+ ```
64
+ And it will have following result
65
+ ```ruby
66
+ testable = ExampleClass.build({"bar" => "value"})
67
+ testable.foo #=> "VALUE"
68
+ ```
24
69
 
25
- TODO: Write usage instructions here
70
+ ## Combining multiple keys
26
71
 
27
- ## Development
72
+ ```ruby
73
+ class ExampleClass
74
+ include Massager
75
+ attribute :foo, "bar", "baz", type: Types::Strict::String do |bar, baz|
76
+ "#{bar} #{baz}"
77
+ end
78
+ end
79
+ ```
80
+ Note that if you pass multiple keys, the modifier block is mandatory
28
81
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
82
+ ```ruby
83
+ testable = ExampleClass.build({"bar" => "bar", "baz" => "baz"})
84
+ testable.foo #=> "bar baz"
85
+ ```
30
86
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
87
+ ## Enum attributes
88
+ If you want to have enum as a result, you will need to use `enum_attribute`
89
+ ```ruby
90
+ class ExampleClass
91
+ include Massager
92
+ enum_attribute :foo, "bar", "baz"
93
+ end
94
+ ```
95
+ ```ruby
96
+ testable = ExampleClass.build({"bar" => "bar", "baz" => "baz"})
97
+ testable.foo #=> ["bar", "baz"]
98
+ ```
32
99
 
33
- ## Contributing
100
+ ## Enum attribute with modifier
101
+ You can apply modifications to the collection
102
+ ```ruby
103
+ class ExampleClass
104
+ include Massager
105
+ enum_attribute :foo, "bar", "baz" do |values|
106
+ values.reverse
107
+ end
108
+ end
109
+ ```
110
+ ```ruby
111
+ testable = ExampleClass.build({"bar" => "bar", "baz" => "baz"})
112
+ testable.foo #=> ["baz", "bar"]
113
+ ```
34
114
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/massager. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
115
+ ## Enum attribute with type check
116
+ You can provide type checks as well
117
+ ```ruby
118
+ class ExampleClass
119
+ include Massager
120
+ enum_attribute :foo, "bar", "baz", type: Types::Strict::Array.member(Types::Strict::String)
121
+ end
122
+ ```
123
+ ```ruby
124
+ testable = ExampleClass.build({"bar" => "bar", "baz" => "baz"})
125
+ testable.foo #=> ["bar", "baz"]
36
126
 
127
+ testable = ExampleClass.build({"bar" => 123, "baz" => "baz"}) # Will raise Dry::Types::ConstraintError
128
+ ```
37
129
 
38
130
  ## License
39
131
 
@@ -0,0 +1,29 @@
1
+ module Massager
2
+ class Attribute
3
+ def initialize(name:, target_keys:, opts: {}, block: nil)
4
+ raise ArgumentError, "If you pass multiple keys, you have to use modifier block" if block.nil? && target_keys.count > 1
5
+ @name, @target_keys, @opts, @block = name, target_keys, opts, block
6
+ end
7
+
8
+ def call(values)
9
+ begin
10
+ values = values.values_at(*target_keys)
11
+ Dry::Monads::Maybe(block).fmap {|block| values = block.call(*values)}
12
+ Dry::Monads::Maybe(opts[:type]).fmap {|type| values = type.call(*values)}
13
+ return_result(*values)
14
+ rescue ArgumentError
15
+ raise ArgumentError, "The result of modifier block should return single element"
16
+ end
17
+ end
18
+
19
+ def return_result(values)
20
+ values
21
+ end
22
+
23
+ def match_schema?(attrs)
24
+ (attrs.keys & target_keys).any?
25
+ end
26
+
27
+ attr_reader :target_keys, :block, :opts, :name
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ module Massager
2
+ class EnumAttribute
3
+ def initialize(name:, target_keys:, opts: {}, block:)
4
+ @name, @target_keys, @opts, @block = name, target_keys, opts, block
5
+ end
6
+
7
+ def call(values)
8
+ values = values.values_at(*target_keys)
9
+ Dry::Monads::Maybe(block).fmap {|block| values = block.call(values)}
10
+ Dry::Monads::Maybe(opts[:type]).fmap {|type| values = type.call(values)}
11
+ raise ArgumentError, "The result of modifier block is not an enum" unless values.respond_to? :each
12
+ values
13
+ end
14
+
15
+ def match_schema?(attrs)
16
+ (attrs.keys & target_keys).any?
17
+ end
18
+
19
+ attr_reader :target_keys, :block, :opts, :name
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Massager
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/massager.rb CHANGED
@@ -3,52 +3,60 @@ require "dry-types"
3
3
  require "dry-monads"
4
4
  require "dry-container"
5
5
 
6
+ require "massager/attributes/attribute"
7
+ require "massager/attributes/enum_attribute"
6
8
 
7
9
  module Massager
8
10
  module ClassMethods
9
- def column(name, target_key, type: nil, &block)
11
+ def attribute(name, *target_keys, **opts, &block)
10
12
  set_container
11
- register_column_info(target_key, name, type, block)
12
- define_setter(target_key)
13
- define_getter(target_key)
13
+ register_attribute(
14
+ Attribute.new(name: name, target_keys: target_keys, opts: opts, block: block)
15
+ )
16
+ define_setter(name)
17
+ define_getter(name)
18
+ end
19
+
20
+ def enum_attribute(name, *target_keys, **opts, &block)
21
+ set_container
22
+ register_attribute(
23
+ EnumAttribute.new(name: name, target_keys: target_keys, opts: opts, block: block)
24
+ )
25
+ define_setter(name)
26
+ define_getter(name)
14
27
  end
15
28
 
16
29
  def build(attrs)
17
- instance = self.new
18
- attrs.each do |k,val|
19
- container = self.container.resolve(k)
20
- instance.send("#{container[:name]}=", val)
30
+ instance = new
31
+ container.each_key do |k|
32
+ attribute = container.resolve(k)
33
+ instance.public_send("#{k}=", attrs) if attribute.match_schema?(attrs)
21
34
  end
22
35
  instance
23
36
  end
24
37
 
25
38
  private
26
39
 
27
- def set_container
28
- self.define_singleton_method(:container) do
29
- @container ||= Dry::Container.new
30
- end
40
+ def register_attribute(attribute)
41
+ container.register(attribute.name) {attribute}
31
42
  end
32
43
 
33
- def define_setter(target_key)
34
- container = self.container.resolve(target_key)
35
- define_method "#{container[:name]}=", Proc.new {|val|
36
- container[:block].fmap {|v| val = v.call(val)}
37
- container[:type].fmap {|v| val = v[val]}
38
- instance_variable_set(:"@#{container[:name]}", val)
44
+ def define_setter(name)
45
+ define_method "#{name}=", Proc.new {|values|
46
+ attribute = self.class.container.resolve(name)
47
+ instance_variable_set(:"@#{name}", attribute.call(values))
39
48
  }
40
49
  end
41
50
 
42
- def define_getter(target_key)
43
- container = self.container.resolve(target_key)
44
- define_method container[:name], Proc.new {
45
- instance_variable_get(:"@#{container[:name]}")
51
+ def define_getter(name)
52
+ define_method name, Proc.new {
53
+ instance_variable_get(:"@#{name}")
46
54
  }
47
55
  end
48
56
 
49
- def register_column_info(target_key, name, type, block)
50
- container.register(target_key) do
51
- {name: name, target_key: target_key, type: Dry::Monads::Maybe(type), block: Dry::Monads::Maybe(block)}
57
+ def set_container
58
+ self.define_singleton_method(:container) do
59
+ @container ||= Dry::Container.new
52
60
  end
53
61
  end
54
62
  end
@@ -57,4 +65,3 @@ module Massager
57
65
  base.extend(ClassMethods)
58
66
  end
59
67
  end
60
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: massager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janis Miezitis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-09-09 00:00:00.000000000 Z
11
+ date: 2016-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-types
@@ -99,6 +99,8 @@ files:
99
99
  - bin/console
100
100
  - bin/setup
101
101
  - lib/massager.rb
102
+ - lib/massager/attributes/attribute.rb
103
+ - lib/massager/attributes/enum_attribute.rb
102
104
  - lib/massager/version.rb
103
105
  - massager.gemspec
104
106
  homepage: http://github.com/janjiss/massager