massager 0.1.1 → 0.2.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: 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