compositor 1.0.1 → 2.0.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: 3a5579d42c800d76ab62fe943c825237b216cf84
4
- data.tar.gz: c74728ad5a2cbb902926c7b7a18d2931a91dae3c
3
+ metadata.gz: 39aa83a1dbde3279e06295e7a5ce005444812d92
4
+ data.tar.gz: b36f918486e1adcd5daa2da24676b96a2fac0d26
5
5
  SHA512:
6
- metadata.gz: 39e18ac43d15623e0c3bdca5b6e6eb82960e99d6f1e5b1cac8786f0df97a7c4d1f5f2b7ae821dc2eb2ca6a97dde7203587923a1e457ab9915229fcc3860cd185
7
- data.tar.gz: 550e32aa5840d1e228d2bab660a0e3fc725219f0e4984275319073106af1a6517fd15bc3e9c4e0db40131dc6fef5dc7cbb648876ff5e43deacefd57f331e3490
6
+ metadata.gz: c878fb457203fdd022a49e991d2dee76ac18bb068b7811a196e03e81222a23b73304740efac40a45c6b632561b639a5b04367481841a9419f0e8a4368f050373
7
+ data.tar.gz: e6850ec7f0c0fd5a0b4c4eab1eb5ad2a69873db8afefd93ffde011b43c61e7f705251df25deb1957f230a493e0551d6e1f601ea434ab611ad757855c34601ca1
data/README.md CHANGED
@@ -3,6 +3,7 @@ Compositor
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/compositor.png)](http://badge.fury.io/rb/compositor)
5
5
  [![Build status](https://secure.travis-ci.org/wanelo/compositor.png)](http://travis-ci.org/wanelo/compositor)
6
+ [![Code Climate](https://codeclimate.com/github/wanelo/compositor.png)](https://codeclimate.com/github/wanelo/compositor)
6
7
 
7
8
  A Composite Design Pattern with a neat DSL for constructing trees of objects in order to render them as a Hash, and subsequently
8
9
  JSON. Used by Wanelo to generate all JSON API responses by compositing multiple objects together in API responses, converting to
@@ -83,9 +84,11 @@ element.
83
84
  So here is how to create a list of users in this way, but explicitly declaring classes:
84
85
 
85
86
  ```ruby
86
- compositor = Compositor::Map.new(view_context,
87
- :collection => @users.map{|user| UserCompositor.new(view_context, user, { :root => true }),
88
- :root => :users
87
+ compositor = ListCompositor.new(view_context,
88
+ :collection => @users.map { |user|
89
+ UserCompositor.new(view_context, user, { :root => true })
90
+ },
91
+ :root => :users)
89
92
  ```
90
93
 
91
94
  When calling ```to_hash``` on the top level compositor, we get:
@@ -121,7 +124,7 @@ of complex responses, as described below.
121
124
  ```UserCompositor``` class, when defined, automatically adds a ```user``` method to the DSL class, which effictively
122
125
  instantiates the new UserCompositor instance, passing the context into it automatically.
123
126
 
124
- Using built-in ```Compositor::Map``` and ```Compositor::List``` we can construct multiple objects into a larger
127
+ Using built-in ```MapCompositor``` and ```ListCompositor``` we can construct multiple objects into a larger
125
128
  hierarchy.
126
129
 
127
130
  In the example below, an application is assumed to define ```StoreCompositor```and ```ProductCompositor``` classes
@@ -164,7 +167,7 @@ similar to ```UserCompositor```, but wrapping ```Store``` and ```Product``` Acti
164
167
  ```
165
168
 
166
169
  Inside the list definition above, ```@products``` is a collection of Products, ```ActiveRecord``` objects,
167
- and the block maps each to a Compositor using ```product()``` method, registered by ProductCompositor.
170
+ and the block maps each to a Compositor using ```product``` method, registered by ProductCompositor.
168
171
 
169
172
  ### Instance Variables
170
173
 
@@ -174,11 +177,11 @@ was defined on ```view_context``` (by Rails, which copies them from the Controll
174
177
  so became automatically available inside DSL. Note that all instance variables must be
175
178
  defined *before* the DSL instance is created.
176
179
 
177
- ### Method Name Collisions in the DSL
180
+ ### Method Names in the DSL
178
181
 
179
- Because DSL uses only the last word of the class name (eg, ```user``` for a class named ```MyModule::UserCompositor```),
180
- there is a possibility of name collisions. In order to prevent that, Compositor will detect if a DSL method is already
181
- defined and throw exception if another class tries to redefine it.
182
+ Compositor will extract the full name of the class and place that name into the DSL. For example, ```MyModule::UserCompositor```
183
+ will define a ```my_module_user``` method in the DSL. To create a method called ```user```, the standard convention
184
+ is to define a class in the global namespace called ```UserCompositor```.
182
185
 
183
186
  If you prefer to have your own ```Compositor``` class hierarchy, or just compositors that should not be added to the
184
187
  DSL, you can name the classes starting with ```Abstract```, such as ```MyModule::AbstractCompositor```.
@@ -1,5 +1,6 @@
1
1
  module Compositor
2
- class MethodAlreadyDefinedError < RuntimeError; end
2
+ class MethodAlreadyDefinedError < RuntimeError;
3
+ end
3
4
 
4
5
  class Base
5
6
  attr_reader :attrs
@@ -33,16 +34,12 @@ module Compositor
33
34
  self.root ? true : false
34
35
  end
35
36
 
36
- def root_class_name
37
- self.class.root_class_name(self.class)
38
- end
39
-
40
- def self.root_class_name(klazz)
41
- klazz.name.gsub(/(.*::)|(Compositor$)/, '').underscore
37
+ def self.original_dsl_name
38
+ self.name.gsub(/(Compositor$)/, '').gsub(/::/, '_').underscore
42
39
  end
43
40
 
44
41
  def self.inherited(subclass)
45
- method_name = root_class_name(subclass)
42
+ method_name = subclass.original_dsl_name
46
43
  unless method_name.eql?("base") || method_name.start_with?("abstract")
47
44
  # check if it's already defined
48
45
  if Compositor::DSL.instance_methods.include?(method_name.to_sym)
@@ -65,6 +62,6 @@ end
65
62
  require_relative 'dsl'
66
63
  require_relative 'composite'
67
64
  require_relative 'leaf'
68
- require_relative 'literal'
69
- require_relative 'list'
70
- require_relative 'map'
65
+ require_relative 'compositors/literal_compositor'
66
+ require_relative 'compositors/list_compositor'
67
+ require_relative 'compositors/map_compositor'
@@ -0,0 +1,5 @@
1
+ class ListCompositor < Compositor::Composite
2
+ def renderer
3
+ @renderer ||= Compositor::Renderer::Iterator
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ class LiteralCompositor < Compositor::Leaf
2
+ attr_accessor :object
3
+
4
+ def initialize(view_context, object = {}, args = {})
5
+ super(view_context, args)
6
+ self.object = object
7
+ end
8
+
9
+ def to_hash
10
+ object
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ class MapCompositor < ::Compositor::Composite
2
+ def renderer
3
+ @renderer ||= Compositor::Renderer::Merged
4
+ end
5
+ end
@@ -1,3 +1,3 @@
1
1
  module Compositor
2
- VERSION = "1.0.1"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -1,28 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Compositor::Base do
4
- describe "#root_class_name" do
5
- it "returns the underscored class name" do
6
- Compositor::Base.root_class_name(Object).should == "object"
7
- end
8
-
4
+ describe "#original_dsl_name" do
9
5
  it "returns the underscored class name with compositor stripped out" do
10
- Compositor::Base.root_class_name(DslStringCompositor).should == "dsl_string"
6
+ DslStringCompositor.original_dsl_name.should == "dsl_string"
11
7
  end
8
+ end
12
9
 
13
- it "raises exception when two subclasses that clash on the same name are defined" do
14
- block = lambda {
15
- # first class
16
- class UserCompositor < Compositor::Leaf
17
- end
18
-
19
- # 2nd class
20
- module ::Foo
21
- class UserCompositor < Compositor::Leaf
10
+ describe '.inherited' do
11
+ describe "when class is defined inside a module" do
12
+ it "returns the underscored class name with compositor stripped out but with the module added" do
13
+ module Exploding
14
+ class ExplosionCompositor < Compositor::Leaf
22
15
  end
23
16
  end
24
- }
25
- expect { block.call }.to raise_error
17
+
18
+ expect(Compositor::DSL.instance_methods).to include(:exploding_explosion)
19
+ end
26
20
  end
27
21
 
28
22
  it "does not add DSL when class name begins with Abstract" do
@@ -39,6 +33,5 @@ describe Compositor::Base do
39
33
  expect { block.call }.not_to raise_error
40
34
  Compositor::DSL.instance_methods.should_not include(:abstract_user)
41
35
  end
42
-
43
36
  end
44
37
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Compositor::List do
3
+ describe ListCompositor do
4
4
  let(:context) { Object.new }
5
5
 
6
6
  it 'returns the generated array with the explicit receiver' do
@@ -1,12 +1,12 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Compositor::Literal do
3
+ describe LiteralCompositor do
4
4
 
5
5
  let(:context) { Object.new }
6
6
 
7
7
  it 'returns the hash its given' do
8
8
  actual = { test: 123 }
9
9
 
10
- Compositor::Literal.new(context, actual).to_hash.should == actual
10
+ LiteralCompositor.new(context, actual).to_hash.should == actual
11
11
  end
12
12
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Compositor::Map do
3
+ describe MapCompositor do
4
4
  let(:context) { Object.new }
5
5
 
6
6
  it 'returns the generated map' do
@@ -34,10 +34,10 @@ describe 'Performance' do
34
34
  10000.times do
35
35
  string = DslStringCompositor.new(context)
36
36
  int = DslIntCompositor.new(context, 3)
37
- list = Compositor::List.new(context,
37
+ list = ListCompositor.new(context,
38
38
  root: :numbers,
39
39
  collection: [1, 2, 3].map! { |n| DslIntCompositor.new(context, n) })
40
- cmp = Compositor::Map.new(context, collection: [string, int, list])
40
+ cmp = MapCompositor.new(context, collection: [string, int, list])
41
41
  cmp.to_hash.should == {:a => "b", :number => 3, :numbers => [{:number => 1}, {:number => 2}, {:number => 3}]}
42
42
  end
43
43
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: compositor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
@@ -9,62 +9,62 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-21 00:00:00.000000000 Z
12
+ date: 2014-02-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: oj
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rspec
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - '>='
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - '>='
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: guard-rspec
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - '>='
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
48
  version: '0'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - '>='
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: rb-fsevent
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - '>='
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: '0'
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - '>='
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0'
70
70
  description: Define simple "compositor" classes that represent your domain objects
@@ -77,10 +77,10 @@ executables: []
77
77
  extensions: []
78
78
  extra_rdoc_files: []
79
79
  files:
80
- - .gitignore
81
- - .pairs
82
- - .rspec
83
- - .travis.yml
80
+ - ".gitignore"
81
+ - ".pairs"
82
+ - ".rspec"
83
+ - ".travis.yml"
84
84
  - Gemfile
85
85
  - Guardfile
86
86
  - LICENSE
@@ -90,21 +90,21 @@ files:
90
90
  - lib/compositor.rb
91
91
  - lib/compositor/base.rb
92
92
  - lib/compositor/composite.rb
93
+ - lib/compositor/compositors/list_compositor.rb
94
+ - lib/compositor/compositors/literal_compositor.rb
95
+ - lib/compositor/compositors/map_compositor.rb
93
96
  - lib/compositor/dsl.rb
94
97
  - lib/compositor/leaf.rb
95
- - lib/compositor/list.rb
96
- - lib/compositor/literal.rb
97
- - lib/compositor/map.rb
98
98
  - lib/compositor/renderer/base.rb
99
99
  - lib/compositor/renderer/iterator.rb
100
100
  - lib/compositor/renderer/merged.rb
101
101
  - lib/compositor/version.rb
102
102
  - spec/compositor/base_spec.rb
103
+ - spec/compositor/compositors/list_compositor_spec.rb
104
+ - spec/compositor/compositors/literal_compositor_spec.rb
105
+ - spec/compositor/compositors/map_compositor_spec.rb
103
106
  - spec/compositor/dsl_spec.rb
104
- - spec/compositor/hash_spec.rb
105
107
  - spec/compositor/leaf_spec.rb
106
- - spec/compositor/list_spec.rb
107
- - spec/compositor/literal_spec.rb
108
108
  - spec/compositor/performance_spec.rb
109
109
  - spec/spec_helper.rb
110
110
  - spec/support/sample_dsl.rb
@@ -118,28 +118,29 @@ require_paths:
118
118
  - lib
119
119
  required_ruby_version: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - '>='
121
+ - - ">="
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
124
  required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  requirements:
126
- - - '>='
126
+ - - ">="
127
127
  - !ruby/object:Gem::Version
128
128
  version: '0'
129
129
  requirements: []
130
130
  rubyforge_project:
131
- rubygems_version: 2.1.11
131
+ rubygems_version: 2.2.0
132
132
  signing_key:
133
133
  specification_version: 4
134
134
  summary: Composite design pattern with a convenient DSL for building JSON/Hashes of
135
135
  complex objects.
136
136
  test_files:
137
137
  - spec/compositor/base_spec.rb
138
+ - spec/compositor/compositors/list_compositor_spec.rb
139
+ - spec/compositor/compositors/literal_compositor_spec.rb
140
+ - spec/compositor/compositors/map_compositor_spec.rb
138
141
  - spec/compositor/dsl_spec.rb
139
- - spec/compositor/hash_spec.rb
140
142
  - spec/compositor/leaf_spec.rb
141
- - spec/compositor/list_spec.rb
142
- - spec/compositor/literal_spec.rb
143
143
  - spec/compositor/performance_spec.rb
144
144
  - spec/spec_helper.rb
145
145
  - spec/support/sample_dsl.rb
146
+ has_rdoc:
@@ -1,7 +0,0 @@
1
- module Compositor
2
- class List < Compositor::Composite
3
- def renderer
4
- @renderer ||= Compositor::Renderer::Iterator
5
- end
6
- end
7
- end
@@ -1,14 +0,0 @@
1
- module Compositor
2
- class Literal < Compositor::Leaf
3
- attr_accessor :object
4
-
5
- def initialize(view_context, object = {}, args = {})
6
- super(view_context, args)
7
- self.object = object
8
- end
9
-
10
- def to_hash
11
- object
12
- end
13
- end
14
- end
@@ -1,7 +0,0 @@
1
- module Compositor
2
- class Map < ::Compositor::Composite
3
- def renderer
4
- @renderer ||= Compositor::Renderer::Merged
5
- end
6
- end
7
- end