ordinary 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1bff706645249ee9b180396fa8dbd97c60de1a32
4
+ data.tar.gz: bef17919f5c25b578de54234e9b79d7611902a5b
5
+ SHA512:
6
+ metadata.gz: c59a7bc904f9b0bcaa687dec7fa6b779cc2b257e615179086ad6d433bd9b320e296a1330950b2261052c10b7ee4b348c9a6ca3ca648d97e2a0ff3579df2db6f0
7
+ data.tar.gz: 544ffa6acca8a2412426b7f4c5dfc8d91a4c03437a4e66fe6be70a5735f049486ec7150a3f8ca25d1d0db5204f1fe23d6a9dbce7cacaaea85e9f3a3a9d47c020
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ordinary.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Takahiro Kondo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,232 @@
1
+ Ordinary
2
+ ========
3
+
4
+ Normalizer for any model
5
+
6
+ Installation
7
+ ------------
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'ordinary'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install ordinary
20
+
21
+ Usage
22
+ -----
23
+
24
+ First, you will include `Ordinary` to the model of the object. Following is an example of using ActiveModel.
25
+
26
+ ```ruby
27
+ require 'ordinary'
28
+
29
+ class Person
30
+ include ActiveModel::Model
31
+ include Ordinary
32
+
33
+ attr_accessor :name
34
+
35
+ normalizes :name do |value|
36
+ value.strip.squeeze(' ')
37
+ end
38
+ end
39
+ ```
40
+
41
+ You can get the normalized value with `#normalize_attribute` or `#normalized_ATTR_NAME`.
42
+
43
+ ```ruby
44
+ person = Person.new(:name => ' Koyomi Araragi ')
45
+ puts person.name # => " Koyomi Araragi "
46
+ puts person.normalize_attribute(:name) # => "Koyomi Araragi"
47
+ puts person.normalized_name # => "Koyomi Araragi"
48
+ ```
49
+
50
+ And you can get the normalized model with `#normalize`.
51
+
52
+ ```ruby
53
+ normalized_person = person.normalize
54
+ puts normalized_person.normalized? # => true
55
+ puts normalized_person.name # => "Koyomi Araragi"
56
+ ```
57
+
58
+ Off course, it doesn't affect the original model.
59
+
60
+ ```ruby
61
+ puts person.normalized? # => false
62
+ puts person.name # => " Koyomi Araragi "
63
+ ```
64
+
65
+ However, if you use `#normalize!`, the original model will also be normalized.
66
+
67
+ How to define normalization
68
+ ---------------------------
69
+
70
+ How to define normalization is from where you include `Ordinary`.
71
+
72
+ ```ruby
73
+ require 'ordinary'
74
+
75
+ class AnyModel
76
+ include Ordinary
77
+
78
+ # define normalization...
79
+ end
80
+ ```
81
+
82
+ Incidentally, in order to enable to read and write to a target attirbute, you must define `#ATTR_NAME` and `#ATTR_NAME=`.
83
+
84
+ Normalization defines with `.normalizes`.
85
+
86
+ ```ruby
87
+ class AnyModel
88
+ # ...
89
+
90
+ attr_accessor :attr1, :attr2
91
+
92
+ normalizes :attr1, :attr2 do |value|
93
+ # process for normalization
94
+ end
95
+
96
+ # ...
97
+ end
98
+ ```
99
+
100
+ You can define in a variety of ways.
101
+
102
+ ```ruby
103
+ class AnyModel
104
+ # ...
105
+
106
+ attr_accessor :attr1, :attr2
107
+
108
+ # specify process with a block
109
+ normalizes :attr1 do |value|
110
+ "#{value}_1"
111
+ end
112
+
113
+ # if define normalization to same attribute, normalization runs in the order
114
+ # in which you defined
115
+ normalizes :attr1 do |value|
116
+ "#{value}_2"
117
+ end
118
+
119
+ # If specify Proc to last argument, define composed unit in the Proc as
120
+ # process of normalization (units described later)
121
+ normalizes :attr2, lambda { lstrip | rstrip }
122
+
123
+ # also specify both block and Proc (position of process of block decides by
124
+ # block unit)
125
+ normalizes :attr2, lambda { block | squeeze(' ') } do |value|
126
+ "#{value}_3"
127
+ end
128
+
129
+ # also specify options
130
+ normalizes :attr2, if: lambda { !attr2.nil? }, with: lambda { block | at(0) } do |value|
131
+ (value.empty? or %w(0 false f).include?(value)) ? 'false' : 'true'
132
+ end
133
+
134
+ # ...
135
+ end
136
+ ```
137
+
138
+ How to create an units module
139
+ -----------------------------
140
+
141
+ You can create a module bundled some units. You'll use `Ordinary::Module` to do so.
142
+
143
+ ```ruby
144
+ require 'ordinary/module'
145
+
146
+ module AnyModule
147
+ extend Ordinary::Module
148
+
149
+ # define the module...
150
+ end
151
+ ```
152
+
153
+ And you can register to use the module with `Ordinary.register`.
154
+
155
+ ```ruby
156
+ require 'ordinary'
157
+
158
+ Ordinary.register(AnyModule)
159
+ ```
160
+
161
+ ### Define an unit
162
+
163
+ An unit can define with `.unit` in the module.
164
+
165
+ ```ruby
166
+ module AnyModule
167
+ # ...
168
+
169
+ unit :some_unit do |value|
170
+ # process for the unit...
171
+ end
172
+
173
+ # ...
174
+ end
175
+ ```
176
+
177
+ You can define in a variety of ways.
178
+
179
+ ```ruby
180
+ module AnyModule
181
+ # ...
182
+
183
+ # specify process with a block
184
+ unit :lstrip do |value|
185
+ value.lstrip
186
+ end
187
+
188
+ # okay as the argument
189
+ unit :rstrip, lambda { |value| value.rstrip }
190
+
191
+ # actually, above examples are okay at follows
192
+ unit :lstrip
193
+
194
+ # as aliasing
195
+ unit :ltrim, :lstrip
196
+
197
+ # by the way, units are defined as module functions, you can also see
198
+ p lstrip # => #<Ordinary::Unit:0x0x007ff6ec8e7610 AnyModule#lstrip>
199
+
200
+ # and compose units by #| (or #>>, #<<)
201
+ unit :strip, lstrip | rstrip
202
+
203
+ # ...
204
+ end
205
+ ```
206
+
207
+ ### Define a dependency
208
+
209
+ If exist dependencies to some libraries to units in the module, will resolve with `.requires`.
210
+
211
+ ```ruby
212
+ module AnyModule
213
+ # ...
214
+
215
+ requires 'nkf'
216
+
217
+ unit :to_half do |value|
218
+ NKF.nkf('-wWZ1', value)
219
+ end
220
+
221
+ # ...
222
+ end
223
+ ```
224
+
225
+ Contributing
226
+ ------------
227
+
228
+ 1. Fork it
229
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
230
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
231
+ 4. Push to the branch (`git push origin my-new-feature`)
232
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/lib/ordinary.rb ADDED
@@ -0,0 +1,160 @@
1
+ require 'ordinary/version'
2
+ require 'ordinary/builder'
3
+ require 'ordinary/normalizer'
4
+ require 'ordinary/module'
5
+
6
+ module Ordinary
7
+
8
+ # Normalize an attribute.
9
+ #
10
+ # @param [Symbol] attr_name an attribute to normalize
11
+ # @param [Symbol] context normalization context. defaults to nil
12
+ # @return [Object] the normalized attribute
13
+ def normalize_attribute(attr_name, context = nil)
14
+ value = __send__(attr_name)
15
+
16
+ unless value.nil?
17
+ self.class.normalizers[attr_name.to_sym].each do |normalizer|
18
+ next unless normalizer.coming_under?(self)
19
+ next unless normalizer.run_at?(context)
20
+ value = normalizer.normalize(value)
21
+ end
22
+ end
23
+
24
+ value
25
+ end
26
+
27
+ # Normalize all attributes and return the normalized object.
28
+ #
29
+ # @param [Symbol] context normalization context. defaults to nil
30
+ # @return [Object] the normalized object
31
+ def normalize(context = nil)
32
+ clone.normalize!(context)
33
+ end
34
+
35
+ # Normalize all attributes distructively.
36
+ #
37
+ # @param [Symbol] context normalization context. defaults to nil
38
+ # @return [Object] self
39
+ def normalize!(context = nil)
40
+ unless normalized?(context)
41
+ self.class.normalizers.keys.each do |attr_name|
42
+ __send__(:"#{attr_name}=", normalize_attribute(attr_name, context))
43
+ end
44
+
45
+ @normalization_context = context
46
+ end
47
+
48
+ self
49
+ end
50
+
51
+ # Determine if self is normalized.
52
+ #
53
+ # @param [Symbol] context normalization context. defaults to nil
54
+ # @return whether self is normalized
55
+ def normalized?(context = nil)
56
+ return false unless instance_variable_defined?(:@normalization_context)
57
+ @normalization_context.nil? or (@normalization_context == context)
58
+ end
59
+
60
+ # Register modules to the context of building.
61
+ #
62
+ # @scope class
63
+ # @param [Array<Ordinary::Module>] modules modules to register
64
+ def self.register(*modules)
65
+ Builder::Context.register(*modules)
66
+ end
67
+
68
+ # Unregister modules from the context of building.
69
+ #
70
+ # @scope class
71
+ # @param [Array<Ordinary::Module>] modules modules to unregister
72
+ def self.unregister(modules)
73
+ Builder::Context.unregister(*modules)
74
+ end
75
+
76
+ def self.included(klass)
77
+ klass.extend(ClassMethods)
78
+
79
+ if defined?(ActiveModel::Validations) and klass.include?(ActiveModel::Validations)
80
+ method = klass.instance_method(:run_validations!)
81
+
82
+ klass.__send__(:define_method, :run_validations!) do
83
+ context = validation_context
84
+ normalized?(context) ? method.bind(self).call : normalize(context).valid?(context)
85
+ end
86
+ end
87
+
88
+ if defined?(ActiveRecord::Base) and klass.include?(ActiveRecord::Base)
89
+ end
90
+ end
91
+
92
+ module ClassMethods
93
+
94
+ # @attribute [r] normalizers
95
+ # @return [Hash<Symbol, Array<Ordinary::Normalizer>>] normalizers for each
96
+ # attribute
97
+ def normalizers
98
+ @normalizers ||= {}
99
+ end
100
+
101
+ # Define normalization for attributes.
102
+ #
103
+ # @example define normalization with a builder for the normalizer
104
+ #
105
+ # normalizes :name, lambda { lstrip }
106
+ # normalizes :name, lambda { lstrip | rstrip }
107
+ #
108
+ # @example define normalization with a block
109
+ #
110
+ # normalizes :name do |value|
111
+ # value.squeeze(' ')
112
+ # end
113
+ #
114
+ # @example define normalization with a builder for the normalizer and a block
115
+ #
116
+ # normalizes :name, -> { lstrip | block | rstrip } do |value|
117
+ # value.squeeze(' ')
118
+ # end
119
+ #
120
+ # @param [Array<Symbol>] attr_names attirubte names to normalize
121
+ # @yield [value] normalize the attribute
122
+ # @yieldparam [Object] value value of the attribute to normalize
123
+ def normalizes(*attr_names, &block)
124
+ attr_names = attr_names.dup
125
+ buil = nil
126
+ options = {}
127
+
128
+ case attr_names.last
129
+ when Proc
130
+ build = attr_names.pop
131
+ when Hash
132
+ options = attr_names.pop.dup
133
+ build = options.delete(:with)
134
+ end
135
+
136
+ unless build or block
137
+ raise ArgumentError, 'process for building a normalizer' \
138
+ '(with the last argument or :with option) or ' \
139
+ 'an unit of a normalizer ' \
140
+ '(with block) are not given'
141
+ end
142
+
143
+ build ||= lambda { block }
144
+ unit = Builder.new(&block).build(&build)
145
+ normalizer = Normalizer.new(options, &unit)
146
+
147
+ attr_names.each do |attr_name|
148
+ raise ArgumentError, "##{attr_name} is not defined" unless method_defined?(attr_name)
149
+ raise ArgumentError, "##{attr_name}= is not defined" unless method_defined?(:"#{attr_name}=")
150
+
151
+ (normalizers[attr_name.to_sym] ||= []) << normalizer
152
+
153
+ define_method :"normalized_#{attr_name}" do |context = nil|
154
+ normalize_attribute(attr_name, context)
155
+ end
156
+ end
157
+ end
158
+
159
+ end
160
+ end
@@ -0,0 +1,79 @@
1
+ require 'ordinary/unit'
2
+ require 'set'
3
+
4
+ module Ordinary
5
+ class Builder
6
+
7
+ def initialize(&block)
8
+ @context = Context.new(block)
9
+ end
10
+
11
+ # @attribute [r] context
12
+ # @return [Ordinary::Builder::Context] the context of building
13
+ attr_reader :context
14
+
15
+ # Build units for a normalizer.
16
+ #
17
+ # @yield build units for a normalizer
18
+ # @return [Ordinary::Unit, Ordinary::Units] units for a normalizer
19
+ def build(&build)
20
+ @context.instance_exec(&build)
21
+ end
22
+
23
+ module Context
24
+ class << self
25
+ attr_reader :current, :modules
26
+ end
27
+
28
+ def self.update(modules)
29
+ @current = Class.new { include *[*modules, Context] }.freeze
30
+ @modules = modules.freeze
31
+ end
32
+ private_class_method :update
33
+
34
+ update(Set.new)
35
+
36
+ def self.register(*modules)
37
+ update(@modules | modules)
38
+ end
39
+
40
+ def self.unregister(*modules)
41
+ update(@modules - modules)
42
+ end
43
+
44
+ def self.new(*args, &block)
45
+ @current.new(*args, &block)
46
+ end
47
+
48
+ def initialize(block = nil)
49
+ @block = block ? Unit.new(nil, &block) : nil
50
+ end
51
+
52
+ def block
53
+ unless @block
54
+ e = BlockNotGiven.new("`block' unit cannot use if a block is not given")
55
+ e.set_backtrace(caller)
56
+ raise e
57
+ end
58
+
59
+ @block
60
+ end
61
+
62
+ def method_missing(method_name, *args, &block)
63
+ e = UnitNotDefined.new("`#{method_name}' unit is not defined")
64
+ e.set_backtrace(caller)
65
+ raise e
66
+ end
67
+
68
+ def inspect
69
+ header = "#{Context.name}:0x%014x" % (object_id << 1)
70
+ module_list = Context.modules.map(&:name).sort * ', '
71
+ with_block = @block ? ' with a block' : ''
72
+ "#<#{header} [#{module_list}]#{with_block}>"
73
+ end
74
+ end
75
+
76
+ class UnitNotDefined < StandardError; end
77
+ class BlockNotGiven < StandardError; end
78
+ end
79
+ end
@@ -0,0 +1,117 @@
1
+ require 'ordinary/unit'
2
+ require 'set'
3
+
4
+ module Ordinary
5
+ module Module
6
+
7
+ # @attribute [r] requirements
8
+ # @return [Ordinary::Module::Requirements] libraries that the module
9
+ # requires
10
+ def requirements
11
+ @requirements ||= Requirements.new
12
+ end
13
+
14
+ # Add libraries to the requirements.
15
+ #
16
+ # @param [Array<String>] libraries required libraries
17
+ #
18
+ # @see Ordinary::Module#requirements
19
+ def requires(*libraries)
20
+ requirements.add(*libraries)
21
+ end
22
+
23
+ # Define an unit for some normalizer.
24
+ #
25
+ # @example define an unit with a block
26
+ #
27
+ # unit :lstrip do |value|
28
+ # value.lstrip
29
+ # end
30
+ #
31
+ # # same as above
32
+ # unit :lstrip, lambda { |value| value.lstrip }
33
+ #
34
+ # @example define an unit simply
35
+ #
36
+ # # call .lstrip of a value
37
+ # unit :lstrip
38
+ #
39
+ # # and named "ltrim"
40
+ # unit :ltrim, :lstrip
41
+ #
42
+ # @example define an unit with existing units
43
+ #
44
+ # unit :lstrip
45
+ # unit :rstrip
46
+ #
47
+ # # use an existing unit
48
+ # unit :ltrim, lstrip
49
+ # unit :rtrim, rstrip
50
+ #
51
+ # # use by combining existing units (by #|, #>> or #<<)
52
+ # unit :trim, ltrim | rtrim
53
+ #
54
+ # @param [Symbol] name name of the unit
55
+ # @param [Symbol] unit
56
+ # @param [Proc] unit process of normalization that the unit plays
57
+ # @param [Ordinary::Unit, Ordinary::Units] unit an existing unit or
58
+ # combination existing units
59
+ # @yield [value, *args] process of normalization that the unit plays
60
+ # @yieldparam [Object] value a value to process
61
+ # @yieldparam [Array<Object>] args additional arguments
62
+ def unit(name, unit = nil, &block)
63
+ unit = unit.to_sym if unit.is_a?(String)
64
+
65
+ unit = if unit.nil? and block.nil?
66
+ unit_by_send(name)
67
+ elsif unit.is_a?(Symbol)
68
+ unit_by_send(unit)
69
+ elsif unit.is_a?(Proc)
70
+ create_unit(&unit)
71
+ elsif block_given?
72
+ create_unit(&block)
73
+ else
74
+ unit
75
+ end
76
+
77
+ unit.owned_by(self, name) unless unit.owned?
78
+ define_method(name) { |*args| args.empty? ? unit : unit.with(*args) }
79
+ module_function name
80
+ end
81
+
82
+ private
83
+
84
+ def unit_by_send(method_name)
85
+ create_unit { |value, *args| value.__send__(method_name, *args) }
86
+ end
87
+
88
+ def create_unit(&process)
89
+ Unit.new(nil, requirements, &process)
90
+ end
91
+
92
+ class Requirements
93
+ def initialize
94
+ @libraries = Set.new
95
+ @loaded = false
96
+ end
97
+
98
+ def add(*libraries)
99
+ @loaded &= !(Set.new(libraries) - @libraries).empty?
100
+ @libraries |= libraries
101
+ end
102
+
103
+ def delete(*libraries)
104
+ @libraries -= libraries
105
+ end
106
+
107
+ def loaded?
108
+ @loaded
109
+ end
110
+
111
+ def load
112
+ @libraries.each(&method(:require))
113
+ @loaded = true
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,46 @@
1
+ module Ordinary
2
+ class Normalizer
3
+
4
+ def initialize(options = {}, &process)
5
+ @determine = extract_determiner(options)
6
+ @context = options[:on]
7
+ @process = process
8
+ end
9
+
10
+ # Normalize a value by the normalizer.
11
+ #
12
+ # @param [Object] value a value to normalize
13
+ # @return [Object] a normalized value
14
+ def normalize(value)
15
+ @process.call(value)
16
+ end
17
+
18
+ # Determine if a model coming under a target of the normalizer.
19
+ #
20
+ # @param [ActiveModel::Model] model a model to determine if be a target of
21
+ # the normalizer
22
+ # @return whether the model is a target of the normalizer
23
+ def coming_under?(model)
24
+ @determine.nil? or !!@determine.call(model)
25
+ end
26
+
27
+ # Determine if
28
+ #
29
+ # @param [Symbol] context a context to determine
30
+ # @return whether
31
+ def run_at?(context)
32
+ @context.nil? or (@context == context)
33
+ end
34
+
35
+ private
36
+
37
+ def extract_determiner(options)
38
+ if determine = options[:if]
39
+ lambda { |model| model.instance_eval(&determine) }
40
+ elsif determine = options[:unless]
41
+ lambda { |model| !model.instance_eval(&determine) }
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,85 @@
1
+ module Ordinary
2
+ module Composable
3
+ def >>(other)
4
+ Units.new([*self, *other])
5
+ end
6
+ alias | >>
7
+
8
+ def <<(other)
9
+ other >> self
10
+ end
11
+
12
+ def owner
13
+ owned? ? "#{@module.name}##{@name}" : 'owner unknown'
14
+ end
15
+
16
+ def owned_by(mod, name)
17
+ @module = mod
18
+ @name = name
19
+ end
20
+
21
+ def owned?
22
+ @module and @name
23
+ end
24
+
25
+ def instance_id
26
+ "#{self.class.name}:0x%014x" % (object_id << 1)
27
+ end
28
+ end
29
+
30
+ class Unit
31
+ include Composable
32
+
33
+ def initialize(original_unit, requirements = nil, arguments = [], &process)
34
+ raise ArgumentError, 'block not supplied' unless block_given?
35
+ @original_unit = original_unit
36
+ @requirements = requirements
37
+ @arguments = arguments
38
+ @process = process
39
+ end
40
+
41
+ attr_reader :requirements
42
+
43
+ attr_reader :arguments
44
+
45
+ attr_reader :process
46
+
47
+ def with(*arguments)
48
+ self.class.new(self, @requirements, arguments, &@process)
49
+ end
50
+
51
+ def to_proc
52
+ @requirements.load if @requirements and !@requirements.loaded?
53
+ args = @arguments + (@original_unit ? @original_unit.arguments : [])
54
+ lambda { |value| @process.call(value, *args) }
55
+ end
56
+
57
+ def inspect
58
+ original_owner = ''
59
+
60
+ if @original_unit
61
+ argument_list = @arguments.map(&:inspect) * ', '
62
+ original_owner = " (#{@original_unit.owner} with [#{argument_list}])"
63
+ end
64
+
65
+ "#<#{instance_id} #{owner}#{original_owner}>"
66
+ end
67
+ end
68
+
69
+ class Units < Array
70
+ include Composable
71
+
72
+ def with(*arguments)
73
+ self.class.new(map { |unit| unit.with(*arguments) })
74
+ end
75
+
76
+ def to_proc
77
+ processes = map(&:to_proc)
78
+ lambda { |value| processes.reduce(value) { |v, p| p.call(v) } }
79
+ end
80
+
81
+ def inspect
82
+ "#<#{instance_id} #{owner} [#{map(&:inspect) * ', '}]>"
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,3 @@
1
+ module Ordinary
2
+ VERSION = '0.0.1'
3
+ end
data/ordinary.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ordinary/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'ordinary'
8
+ spec.version = Ordinary::VERSION
9
+ spec.authors = ['Takahiro Kondo']
10
+ spec.email = ['heartery@gmail.com']
11
+ spec.description = %q{It normalizes nondistructively specified attributes of any model}
12
+ spec.summary = %q{Normalizer for any model}
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'rake'
22
+ spec.add_development_dependency 'rspec'
23
+ spec.add_development_dependency 'activemodel'
24
+ end
@@ -0,0 +1,137 @@
1
+ require 'ordinary/builder'
2
+
3
+ describe Ordinary::Builder do
4
+ describe '#context' do
5
+ subject { described_class.new { }.context }
6
+
7
+ it { should be_an(Ordinary::Builder::Context.current) }
8
+ its(:block) { should_not be_nil }
9
+ end
10
+
11
+ describe '#build' do
12
+ it '' do
13
+ end
14
+
15
+ context '' do
16
+ # it '' do
17
+ # build = lambda { a }
18
+ # builder = Ordinary::Builder.new(build)
19
+ # builder.build
20
+ # end
21
+ end
22
+ end
23
+ end
24
+
25
+ describe Ordinary::Builder::Context do
26
+ before { described_class.__send__(:update, Set.new) }
27
+
28
+ def change_for_current_ancestors(*modules)
29
+ change(described_class, :current) do
30
+ described_class.current.ancestors.select { |mod| modules.include?(mod) }
31
+ end
32
+ end
33
+
34
+ def change_for_modules
35
+ change(described_class, :modules)
36
+ end
37
+
38
+ describe '.register' do
39
+ it do
40
+ expect {
41
+ described_class.register(Math)
42
+ }.to change_for_current_ancestors(Math).from([]).to([Math])
43
+ end
44
+
45
+ it do
46
+ expect {
47
+ described_class.register(Math)
48
+ }.to change_for_modules.from(Set.new).to(Set.new([Math]))
49
+ end
50
+ end
51
+
52
+ describe '.unregister' do
53
+ before { described_class.register(Math) }
54
+
55
+ it do
56
+ expect {
57
+ described_class.unregister(Math)
58
+ }.to change_for_current_ancestors(Math).from([Math]).to([])
59
+ end
60
+
61
+ it do
62
+ expect {
63
+ described_class.unregister(Math)
64
+ }.to change_for_modules.from(Set.new([Math])).to(Set.new)
65
+ end
66
+ end
67
+
68
+ describe '.new' do
69
+ before do
70
+ @original = described_class.current
71
+ described_class.instance_variable_set(:@current, Class.new)
72
+ end
73
+
74
+ after do
75
+ described_class.instance_variable_set(:@current, @original)
76
+ end
77
+
78
+ subject { described_class.new }
79
+
80
+ it { should be_a(described_class.current) }
81
+
82
+ it "should call #{described_class}.current.new with same arguments and same block" do
83
+ described_class.current.should_receive(:new).with('arg1', 'arg2').and_yield
84
+ described_class.new('arg1', 'arg2') { }
85
+ end
86
+ end
87
+
88
+ describe '#block' do
89
+ let (:sample_block) { lambda { } }
90
+
91
+ subject { context.block }
92
+
93
+ context 'with a block at construction' do
94
+ let (:context) { described_class.new(sample_block) }
95
+
96
+ it { should be_an(Ordinary::Unit) }
97
+ its(:process) { should be(sample_block) }
98
+ end
99
+
100
+ context 'with no block at construction' do
101
+ let (:context) { described_class.new }
102
+
103
+ it { expect { subject }.to raise_error(Ordinary::Builder::BlockNotGiven) }
104
+ end
105
+ end
106
+
107
+ describe '#undefined_method' do
108
+ it do
109
+ expect {
110
+ described_class.new.undefined_method
111
+ }.to raise_error(Ordinary::Builder::UnitNotDefined, "`undefined_method' unit is not defined")
112
+ end
113
+ end
114
+
115
+ describe '#inspect' do
116
+ let (:header) { "#{described_class.name}:0x%014x" % (context.object_id << 1) }
117
+ let (:module_list) { modules.map(&:name).sort * ', ' }
118
+ let (:modules) { [Math, Enumerable] }
119
+
120
+ subject { context.inspect }
121
+
122
+ before { described_class.register(*modules) }
123
+ after { described_class.unregister(*modules) }
124
+
125
+ context 'with a block at construction' do
126
+ let (:context) { described_class.new(lambda { }) }
127
+
128
+ it { should be == "#<#{header} [#{module_list}] with a block>" }
129
+ end
130
+
131
+ context 'with no block at construction' do
132
+ let (:context) { described_class.new }
133
+
134
+ it { should be == "#<#{header} [#{module_list}]>" }
135
+ end
136
+ end
137
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ordinary
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Takahiro Kondo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activemodel
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: It normalizes nondistructively specified attributes of any model
56
+ email:
57
+ - heartery@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/ordinary.rb
68
+ - lib/ordinary/builder.rb
69
+ - lib/ordinary/module.rb
70
+ - lib/ordinary/normalizer.rb
71
+ - lib/ordinary/unit.rb
72
+ - lib/ordinary/version.rb
73
+ - ordinary.gemspec
74
+ - spec/ordinary/builder_spec.rb
75
+ homepage: ''
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.0.3
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Normalizer for any model
99
+ test_files:
100
+ - spec/ordinary/builder_spec.rb