alter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 alter.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 David Baldwin
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.
@@ -0,0 +1,116 @@
1
+ # Alter
2
+
3
+ Passing something like a blog post through many complex filters (Markdown, Liquid, regex, Nokogiri, etc) can get ugly and difficult to test and debug. Alter enforces structure and consistency by moving each filter to easy-to-write processor classes. It also keeps a handy history of all "alterations". The source is a mere 50 lines of code, so it should be easy to read and extend.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'alter'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install alter
18
+
19
+ ## Usage
20
+
21
+ Suppose you are building a blog and you want to run posts through a number of filters when converting to HTML. You might run it through Liquid, then Markdown, then do some crazy Nokogiri stuff, then rewrite YouTube URLs to embedded videos, then sanitize, do some regex replaces, etc. And maybe you want to run it through only some filters in one area of the site, but all filters in other areas. This can quickly get ugly and disorganized.
22
+
23
+ Alter gives you structure and consistency by passing text (or really anything) through easy to write processor classes. All you need to do is inherit from `Alter::Processor` and provide an `output` method.
24
+
25
+ <pre lang="ruby"><code>
26
+ class KumbayaProcessor &#60; Alter::Processor
27
+ def output
28
+ input.gsub("sucks", "is great")
29
+ end
30
+ end
31
+ </code></pre>
32
+
33
+ You will already have access to the `input` attribute. You are simply delivering the `output` based upon the `input`. To use the processor, you will first create a new Alter item which will setup that initial `input` value.
34
+
35
+ <pre lang="ruby"><code>
36
+ text = Alter::Item.new "Your language sucks"
37
+ </code></pre>
38
+
39
+ Now you can run that item through the processor by passing the `KumbayaProcessor` class to the process method. The process method also accepts an array of processors.
40
+
41
+ <pre lang="ruby"><code>
42
+ text.process KumbayaProcessor
43
+ # result: "Your language is great"
44
+ </code></pre>
45
+
46
+ You will also have access to any `options` passed to the processor. Here is a class making use of `options`.
47
+
48
+ <pre lang="ruby"><code>
49
+ class EligibilityProcessor &#60; Alter::Processor
50
+ def output
51
+ if options[:age] >= 35
52
+ input + " and you could run for President"
53
+ else
54
+ input + " but you're too young to be President"
55
+ end
56
+ end
57
+ end
58
+
59
+ text = Alter::Item.new "Your language sucks", :age => 37
60
+ text.process [KumbayaProcessor, EligibilityProcessor]
61
+ # result: "Your language is great and you could run for President"
62
+ </code></pre>
63
+
64
+ You can just as easily chain or separate these process calls. Options can also be passed to the process method if you only want them available to specific processors.
65
+
66
+ <pre lang="ruby"><code>
67
+ text = Alter::Item.new "Your language sucks"
68
+ text.process KumbayaProcessor
69
+ text.process EligibilityProcessor, :age => 33
70
+ # result: "Your language is great but you're too young to be President"
71
+ </code></pre>
72
+
73
+ ### History
74
+
75
+ Alter keeps a history of every "alteration" made to the original input and stores it in the `history` array.
76
+
77
+ <pre lang="ruby"><code>
78
+ pp text.history.collect {|h| {:processor => h.processor, :input => h.input, :output => h.output, :options => h.options, :meta => h.meta}}
79
+ </code></pre>
80
+
81
+ <pre lang="console"><code>
82
+ result:
83
+ [{:processor=>KumbayaProcessor,
84
+ :input=>"Your language sucks",
85
+ :output=>"Your language is great",
86
+ :options=>{},
87
+ :meta=>nil},
88
+ {:processor=>EligibilityProcessor,
89
+ :input=>"Your language is great",
90
+ :output=>"Your language is great but you're too young to be President",
91
+ :options=>{:age=>33},
92
+ :meta=>nil}]
93
+ </code></pre>
94
+
95
+ ### Metadata
96
+
97
+ Extra metadata can be written to the history by providing a `meta` method in the processor class.
98
+
99
+ <pre lang="ruby"><code>
100
+ class UselessProcessor &#60; Alter::Processor
101
+ def meta
102
+ {
103
+ :random => "This is so #{rand(1000)}",
104
+ :data => "This is so meta"
105
+ }
106
+ end
107
+ end
108
+ </code></pre>
109
+
110
+ ## Contributing
111
+
112
+ 1. Fork it
113
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
114
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
115
+ 4. Push to the branch (`git push origin my-new-feature`)
116
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task default: :spec
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/alter/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["David Baldwin"]
6
+ gem.email = ["baldwindavid@gmail.com"]
7
+ gem.description = %q{Enforce structure by moving content filters to easy-to-write processor classes}
8
+ gem.summary = %q{Alter enforces structure by moving content filters to easy-to-write processor classes}
9
+ gem.homepage = ""
10
+
11
+ gem.add_development_dependency "rspec"
12
+
13
+ gem.files = `git ls-files`.split($\)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = "alter"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = Alter::VERSION
19
+ end
@@ -0,0 +1,54 @@
1
+ require "alter/version"
2
+
3
+ module Alter
4
+
5
+ class Item
6
+ attr_accessor :value, :history, :options
7
+ attr_reader :input
8
+
9
+ def initialize(input, options = {})
10
+ @input = input
11
+ @value = input
12
+ @options = options
13
+ @history = []
14
+ end
15
+
16
+ def process(processors = [], mergeable_options = {})
17
+ merged_options = options.merge(mergeable_options)
18
+
19
+ [processors].flatten.each do |processor|
20
+ run_processor(processor.new(value, merged_options))
21
+ end
22
+
23
+ value
24
+ end
25
+
26
+ def run_processor(processor)
27
+ self.value = processor.output
28
+ self.history << Alter::Alteration.new(:processor => processor.class, :input => processor.input, :output => processor.output, :options => processor.options, :meta => processor.meta)
29
+ end
30
+ end
31
+
32
+ class Alteration
33
+ attr_accessor :processor, :input, :output, :options, :meta
34
+
35
+ def initialize(attrs = {})
36
+ attrs.each { |k, v| self.send("#{k}=", v) }
37
+ end
38
+ end
39
+
40
+ class Processor
41
+ attr_accessor :output, :meta
42
+ attr_reader :input, :options
43
+
44
+ def initialize(input, options = {})
45
+ @input = input
46
+ @options = options
47
+ end
48
+
49
+ def output
50
+ input
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,3 @@
1
+ module Alter
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,95 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Item" do
4
+
5
+ before :each do
6
+
7
+ class TextProcessor < Alter::Processor
8
+ def output
9
+ input + " + output"
10
+ end
11
+
12
+ def meta
13
+ {
14
+ :color => "blue",
15
+ :rand => rand(1000)
16
+ }
17
+ end
18
+ end
19
+
20
+ class FirstProcessor < Alter::Processor
21
+ def output
22
+ input + " + first"
23
+ end
24
+ end
25
+
26
+ class SecondProcessor < Alter::Processor
27
+ def output
28
+ input + " + second"
29
+ end
30
+ end
31
+
32
+ class EligibilityProcessor < Alter::Processor
33
+ def output
34
+ if options[:age] >= 35
35
+ input + " + President eligible"
36
+ else
37
+ input + " + Too young to be President"
38
+ end
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ it "should update the value based upon a custom output method in a processor" do
45
+ @item = Alter::Item.new "Initial text"
46
+ @item.process TextProcessor
47
+ @item.value.should == "Initial text + output"
48
+ end
49
+
50
+ it "should allow an array of processors to be passed via the process method" do
51
+ @item = Alter::Item.new "Initial text"
52
+ @item.process [FirstProcessor, SecondProcessor]
53
+ @item.value.should == "Initial text + first + second"
54
+ end
55
+
56
+ it "should allow processors to be chained" do
57
+ @item = Alter::Item.new "Initial text"
58
+ @item.process FirstProcessor
59
+ @item.value.should == "Initial text + first"
60
+ @item.process SecondProcessor
61
+ @item.value.should == "Initial text + first + second"
62
+ end
63
+
64
+ it "should write history to the item" do
65
+ @item = Alter::Item.new "Initial text"
66
+ @item.process [FirstProcessor, SecondProcessor]
67
+ @item.history.size.should == 2
68
+ end
69
+
70
+ it "should attach meta data to the history if provided" do
71
+ @item = Alter::Item.new "Initial text"
72
+ @item.process TextProcessor
73
+ @item.history.first.meta[:color].should == "blue"
74
+ end
75
+
76
+ it "should write a static alteration record to the history" do
77
+ @item = Alter::Item.new "Initial text"
78
+ @item.process TextProcessor
79
+ first_request = @item.history.first.meta[:rand]
80
+ @item.history.first.meta[:rand] == first_request
81
+ end
82
+
83
+ it "should allow passing options via the item" do
84
+ @item = Alter::Item.new "Initial text", :age => 36
85
+ @item.process EligibilityProcessor
86
+ @item.value.should == "Initial text + President eligible"
87
+ end
88
+
89
+ it "should allow passing options via the process method" do
90
+ @item = Alter::Item.new "Initial text"
91
+ @item.process EligibilityProcessor, :age => 32
92
+ @item.value.should == "Initial text + Too young to be President"
93
+ end
94
+
95
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Processor" do
4
+
5
+ before :each do
6
+
7
+ class TextProcessor < Alter::Processor
8
+ def output
9
+ input + " + output"
10
+ end
11
+ end
12
+
13
+ class UselessProcessor < Alter::Processor
14
+ end
15
+
16
+ class EligibilityProcessor < Alter::Processor
17
+ def output
18
+ if options[:age] >= 35
19
+ input + " + President eligible"
20
+ else
21
+ input + " + Too young to be President"
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ it "should produce an output based upon a custom output method" do
29
+ @processor = TextProcessor.new "Initial text"
30
+ @processor.output.should == "Initial text + output"
31
+ end
32
+
33
+ it "should have an output equal to its input if no custom output method is provided" do
34
+ @processor = UselessProcessor.new "Initial text"
35
+ @processor.output.should == "Initial text"
36
+ end
37
+
38
+ it "should allow changing output based upon options" do
39
+ @processor = EligibilityProcessor.new "Initial text", :age => 42
40
+ @processor.output.should == "Initial text + President eligible"
41
+ end
42
+
43
+
44
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'alter'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - David Baldwin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-23 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70266420215180 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70266420215180
25
+ description: Enforce structure by moving content filters to easy-to-write processor
26
+ classes
27
+ email:
28
+ - baldwindavid@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - .gitignore
34
+ - Gemfile
35
+ - LICENSE
36
+ - README.md
37
+ - Rakefile
38
+ - alter.gemspec
39
+ - lib/alter.rb
40
+ - lib/alter/version.rb
41
+ - spec/item_spec.rb
42
+ - spec/processor_spec.rb
43
+ - spec/spec_helper.rb
44
+ homepage: ''
45
+ licenses: []
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 1.8.10
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Alter enforces structure by moving content filters to easy-to-write processor
68
+ classes
69
+ test_files:
70
+ - spec/item_spec.rb
71
+ - spec/processor_spec.rb
72
+ - spec/spec_helper.rb