encoder 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ *~
7
+ *.gem
8
+ tmp
9
+ .yardoc
10
+ doc/*
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Jon Morton
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,44 @@
1
+ Encode
2
+ =========
3
+
4
+ Encode makes it easy to go from codes to meaningful strings.
5
+
6
+ Example
7
+ =======
8
+
9
+ Suppose you have a task in one of three possible states: pending, active, finished. When you store tasks, you'd like to have the state represented as P for pending, A for active, and F, for finished. However, you don't want to worry about the details of turning a state into a specific character.
10
+
11
+ t = Task.new('feed the cat')
12
+
13
+ # By default
14
+ t.status = Status::Pending
15
+ t.status # => 'P'
16
+ t.status.decode # => 'Pending'
17
+
18
+ # You'd probably encapsulate this in a method though wouldn't you?
19
+ t.finish!
20
+
21
+ # How should that be implemented though?
22
+ @status = 'f'
23
+ @status = 'finished'
24
+ @status = Task::Status::Finished
25
+
26
+ However, you want to store the state as a single character behind the scenes without having to define a bunch of custom getters or setters.
27
+
28
+ class Task
29
+ code :status do
30
+ Status::Pending = "P"
31
+ Status::Active = "A"
32
+ Status::Finished = "F"
33
+ end
34
+ end
35
+
36
+ To Do
37
+ =====
38
+
39
+ [ ] Auto-mixin on init
40
+ [ ] Make a proper gem
41
+ [ ] Choose a better name
42
+ [ ] Use shoulda or rspec (maybe)
43
+
44
+ Copyright (c) 2010 Jon Morton, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the encode plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the encode plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'Encode'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ begin
26
+ require 'jeweler'
27
+ Jeweler::Tasks.new do |gemspec|
28
+ gemspec.name = "encoder"
29
+ gemspec.summary = "Make magic numbers and letters meaningful."
30
+ gemspec.description = "Simplify turning abbreviations into descriptions and vice versa."
31
+ gemspec.email = "jon.morton@gmail.com "
32
+ gemspec.homepage = "http://github.com/jmorton/encoder"
33
+ gemspec.authors = ["Jon Morton"]
34
+ end
35
+ Jeweler::GemcutterTasks.new
36
+ rescue LoadError
37
+ puts "Jeweler not available. Install it with: gem install jeweler"
38
+ end
39
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
data/lib/encoder.rb ADDED
@@ -0,0 +1,92 @@
1
+ module Encoder
2
+
3
+ def self.included(base)
4
+ base.class_eval do
5
+ extend ClassMethods
6
+ end
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ #
12
+ # Creates getter and setter methods for an attribute. The getter
13
+ # returns a 'decodable' string that provides more meaning.
14
+ #
15
+ # Example:
16
+ #
17
+ # class Task
18
+ # include Encoder
19
+ # code :priority do
20
+ # Priority::Low = "L"
21
+ # end
22
+ # end
23
+ #
24
+ # t = Task.new
25
+ # t.priority = Priority::Low
26
+ # t.priority # => "L"
27
+ # t.priority.decode # => "Low"
28
+ #
29
+ def code(attribute_name, &block)
30
+
31
+ # Create a 'namespace' for constants
32
+ const_set(attribute_name.to_s.camelcase, Module.new)
33
+
34
+ # Expecting constants to be assigned values.
35
+ yield
36
+
37
+ # create setter for attribute
38
+ self.send(:define_method, "#{attribute_name}=") do |arg|
39
+
40
+ # At the end of this method, the underlying attribute will be set
41
+ # to the value of this variable.
42
+ encoded_value = nil
43
+
44
+ # Retrieve the module where the constants for this attribute are defined.
45
+ namespace = self.class.const_get(attribute_name.to_s.camelcase)
46
+
47
+ # Since the given value might not match the constant name exactly
48
+ # (because of case sensitivity or white space variations) we
49
+ # normalize it a bit.
50
+ normalized = arg && arg.gsub(/\s+/,'').downcase
51
+
52
+ # Now we look for a constant whose name or actual value match the
53
+ # normalized argument. We 'tap' whatever constant name is found
54
+ # and lookup the actual value.
55
+ namespace.constants.find do |const_name|
56
+ normalized == const_name.downcase ||
57
+ normalized == namespace.const_get(const_name).downcase
58
+ end.tap do |match|
59
+ encoded_value = namespace.const_get(match) if match
60
+ end
61
+
62
+ # Set the value to whatever we found, possibly nil
63
+ self.write_attribute(attribute_name, encoded_value)
64
+ end
65
+
66
+ # create getter for attribute
67
+ self.send(:define_method, attribute_name) do
68
+
69
+ encoded_attribute = self.read_attribute(attribute_name)
70
+
71
+ namespace = self.class.const_get(attribute_name.to_s.camelcase)
72
+
73
+ decoded_value = namespace.constants.select do |constant|
74
+ namespace.const_get(constant) == encoded_attribute
75
+ end.first
76
+
77
+ encoded_attribute.instance_variable_set(:@decoding, decoded_value)
78
+
79
+ class << encoded_attribute
80
+ def decode
81
+ @decoding && @decoding.underscore.titleize
82
+ end
83
+ end
84
+
85
+ return encoded_attribute
86
+ end # -- dynamic getter method
87
+
88
+ end # -- code()
89
+
90
+ end
91
+
92
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ # Include hook code here
2
+ require File.join(File.dirname(__FILE__), *%w[.. lib encoder])
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :encoder do
3
+ # # Task goes here
4
+ # end
data/test/database.rb ADDED
@@ -0,0 +1,36 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'rubygems'
4
+ require 'active_record'
5
+ gem 'sqlite3-ruby'
6
+
7
+ require File.dirname(__FILE__) + '/../rails/init'
8
+
9
+ ActiveRecord::Base.logger = Logger.new('/tmp/encoder.log')
10
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => '/tmp/encoder.sqlite')
11
+ ActiveRecord::Migration.verbose = false
12
+ ActiveRecord::Base.default_timezone = :utc if Time.zone.nil?
13
+
14
+ ActiveRecord::Schema.define do
15
+ create_table :tasks, :force => true do |table|
16
+ table.string :status
17
+ table.string :priority
18
+ end
19
+ end
20
+
21
+ class Task < ActiveRecord::Base
22
+ include ::Encoder
23
+
24
+ code :status do
25
+ Status::New = "N"
26
+ Status::Pending = "P"
27
+ Status::Finished = "F"
28
+ Status::OverDue = "O"
29
+ end
30
+
31
+ code :priority do
32
+ Priority::High = "H"
33
+ Priority::Low = "L"
34
+ end
35
+
36
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../test_helper'))
2
+
3
+ class EncoderTest < ActiveSupport::TestCase
4
+
5
+ test "setting an attribute using a constant persists the encoding" do
6
+ task = ::Task.new
7
+ task.status = Task::Status::New
8
+ task.save
9
+
10
+ db_task = ::Task.first
11
+ assert db_task.status == 'N'
12
+ end
13
+
14
+ test "setting an attribute using a description persists the correct encoding" do
15
+ task = ::Task.new
16
+ task.status = 'New'
17
+ task.save
18
+
19
+ db_task = ::Task.first
20
+ assert db_task.status == 'N'
21
+ assert db_task.status.decode == 'New'
22
+ end
23
+
24
+ end
@@ -0,0 +1,13 @@
1
+ ENV['RAILS_ENV'] = 'test'
2
+ ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..'
3
+
4
+ require 'test/unit'
5
+ require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb'))
6
+
7
+ require 'rubygems'
8
+ require 'active_support'
9
+ require 'active_support/test_case'
10
+ require 'test/unit'
11
+
12
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/encoder'))
13
+ require File.expand_path(File.join(File.dirname(__FILE__), 'database'))
@@ -0,0 +1,69 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../test_helper'))
2
+
3
+ class EncoderTest < ActiveSupport::TestCase
4
+
5
+ test "setting an attribute using a constant" do
6
+ task = ::Task.new
7
+ task.status = Task::Status::New
8
+ assert task.status == Task::Status::New
9
+ end
10
+
11
+ test "setting an attribute using a verbose value" do
12
+ task = ::Task.new
13
+ task.status = "New"
14
+ assert task.status == Task::Status::New
15
+ end
16
+
17
+ test "setting an attribute using a an invalid value overwrites a valid one" do
18
+ task = ::Task.new
19
+ task.status = "New"
20
+ task.status = "Invalid"
21
+ assert task.status == nil
22
+ end
23
+
24
+ test "decoding an attribute should match the constant name" do
25
+ task = ::Task.new
26
+ task.status = Task::Status::New
27
+ assert task.status.decode == 'New'
28
+ end
29
+
30
+ test "encoding a description ignores caps" do
31
+ task = ::Task.new
32
+ task.status = 'new'
33
+ assert task.status == Task::Status::New
34
+ task.status = 'NEW'
35
+ assert task.status == Task::Status::New
36
+ end
37
+
38
+ test "encoding a multiword description" do
39
+ task = ::Task.new
40
+ task.status = 'over due'
41
+ assert task.status == Task::Status::OverDue
42
+ end
43
+
44
+ test "decoding a multiword description" do
45
+ task = ::Task.new
46
+ task.status = Task::Status::OverDue
47
+ assert task.status.decode == 'Over Due'
48
+ end
49
+
50
+ test "setting an encoded attribute to nil" do
51
+ task = ::Task.new
52
+ task.status = nil
53
+ assert task.status == nil
54
+ end
55
+
56
+ test "a code's attribute name corresponds to a camelcased namespace" do
57
+ task = ::Task.new
58
+
59
+ class ::Task
60
+ code :foo_bar do
61
+ FooBar::Baz = 1
62
+ FooBar::Buzz = 2
63
+ end
64
+ end
65
+
66
+ assert Task.const_defined?(:FooBar)
67
+ end
68
+
69
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: encoder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jon Morton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-03-20 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Simplify turning abbreviations into descriptions and vice versa.
17
+ email: "jon.morton@gmail.com "
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - .gitignore
26
+ - MIT-LICENSE
27
+ - README
28
+ - Rakefile
29
+ - VERSION
30
+ - install.rb
31
+ - lib/encoder.rb
32
+ - rails/init.rb
33
+ - tasks/encoder_tasks.rake
34
+ - test/database.rb
35
+ - test/functional/encoder_test.rb
36
+ - test/test_helper.rb
37
+ - test/unit/encoder_test.rb
38
+ - uninstall.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/jmorton/encoder
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --charset=UTF-8
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.3.5
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Make magic numbers and letters meaningful.
67
+ test_files:
68
+ - test/database.rb
69
+ - test/functional/encoder_test.rb
70
+ - test/test_helper.rb
71
+ - test/unit/encoder_test.rb