engine-rea 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,3 +2,36 @@ ENGINE-REA
2
2
  ===
3
3
 
4
4
  Rails Engine for MDA pattern Resource Event Agent
5
+
6
+ What's REA
7
+ -----------
8
+
9
+ Resources, events, agents (REA) is a model of how an accounting system can be re-engineered for the computer age. REA was originally proposed in 1982 by William E. McCarthy as a generalized accounting model, and contained the concepts of resources, events and agents.
10
+
11
+ see [REA model on wikipedia](http://en.wikipedia.org/wiki/Resources,_events,_agents)
12
+
13
+ REA is a popular model in teaching accounting information systems (AIS). But it is rare in business practice—companies cannot easily dismantle their legacy systems to meet REA's radical demands. REA has never actually been implemented, it is a data model primarily, the processing model is still vague (see Huang Wei-Peng 2005).
14
+
15
+ The REA model gets rid of many accounting objects that are not necessary in the computer age. Most visible of these are debits and credits—double-entry bookkeeping disappears in an REA system. Many general ledger accounts also disappear, at least as persistent objects; e.g., accounts receivable or accounts payable. The computer can generate these accounts in real time using source document records.
16
+
17
+ REA treats the accounting system as a virtual representation of the actual business. In other words, it creates computer objects that directly represent real-world-business objects. In computer science terms, REA is an ontology. The real objects included in the REA model are:
18
+
19
+ * goods, services or money, i.e., resources
20
+ * business transactions or agreements that affect resources, i.e., events
21
+ * people or other human agencies (other companies, etc.), i.e., agents
22
+
23
+ The Aim of The Project
24
+ ----------------------
25
+ This project added useful functions to ActiveRecord, aim to support easy modeling with REA ontology.
26
+ Provide straight forward DSLs that follows Structural and Behavioral patterns defined in REA.
27
+
28
+ see https://github.com/lazing/engine-rea/wiki
29
+
30
+ # REA Ontology
31
+
32
+ “An ontology is a study of the categories of things that exist or may exist
33
+ in some domain” (Sowa 1999). Ontological categories define the concepts
34
+ that exist in the domain, as well as relationships between these concepts.
35
+ Geerts and McCarthy (Geerts, McCarthy 2000, 2002) formulated REA as
36
+ an ontology for business systems. The REA ontological categories are il-
37
+ lustrated in Fig. 226.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.1
@@ -1,8 +1,9 @@
1
1
  module Rea
2
2
  class Category < ActiveRecord::Base
3
+ include ::Rea::AspectType::Classification::Category
3
4
  belongs_to :category_type
4
- belongs_to :parent_category, :class_name=>self.name
5
+ belongs_to :parent_category, :class_name=>self.name, :foreign_key=>:category_id
5
6
  has_many :child_categories, :class_name=>self.name
6
- attr_accessible :name
7
+ attr_accessible :name, :category_type_id, :category_id
7
8
  end
8
9
  end
@@ -1,7 +1,7 @@
1
1
  module Rea
2
2
  class CategoryType < ActiveRecord::Base
3
- belongs_to :group, :polymorphic=>true
3
+ include ::Rea::AspectType::Classification::CategoryType
4
4
  has_many :categories
5
- attr_accessible :group_type, :name, :system, :automatic, :multiple
5
+ attr_accessible :name, :system, :automatic, :multiple
6
6
  end
7
7
  end
@@ -2,12 +2,10 @@ class CreateReaCategoryTypes < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :rea_category_types do |t|
4
4
  t.string :name
5
- t.references :group
6
- t.string :group_type
7
5
  t.boolean :system
8
6
  t.boolean :automatic
9
7
  t.boolean :multiple
10
8
  end
11
- add_index :rea_category_types, [:group_id, :group_type]
9
+ add_index :rea_category_types, :name
12
10
  end
13
11
  end
data/engine-rea.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "engine-rea"
8
- s.version = "0.1.1"
8
+ s.version = "0.2.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ryan Wong"]
12
- s.date = "2012-06-06"
12
+ s.date = "2012-06-19"
13
13
  s.description = "\n follow REA model\n\t"
14
14
  s.email = "lazing@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -43,13 +43,31 @@ Gem::Specification.new do |s|
43
43
  "db/migrate/20120605030708_create_rea_group_entities.rb",
44
44
  "db/migrate/20120605082028_create_rea_identifiers.rb",
45
45
  "engine-rea.gemspec",
46
+ "lib/engine-rea.rb",
46
47
  "lib/generators/rea/install/USAGE",
47
48
  "lib/generators/rea/install/install_generator.rb",
48
49
  "lib/rea.rb",
50
+ "lib/rea/aspect_type.rb",
51
+ "lib/rea/aspect_type/base.rb",
52
+ "lib/rea/aspect_type/classification_aspect.rb",
53
+ "lib/rea/aspect_type/description.rb",
54
+ "lib/rea/aspect_type/due_date_type.rb",
55
+ "lib/rea/aspect_type/identifier_setup.rb",
49
56
  "lib/rea/dsl.rb",
50
57
  "lib/rea/dsl/behavioral.rb",
51
58
  "lib/rea/dsl/structural.rb",
52
59
  "lib/rea/engine.rb",
60
+ "lib/rea/meta_type.rb",
61
+ "lib/rea/meta_type/agent.rb",
62
+ "lib/rea/meta_type/commitment.rb",
63
+ "lib/rea/meta_type/contract.rb",
64
+ "lib/rea/meta_type/entity.rb",
65
+ "lib/rea/meta_type/event.rb",
66
+ "lib/rea/meta_type/group.rb",
67
+ "lib/rea/meta_type/resource.rb",
68
+ "lib/rea/meta_type/schedule.rb",
69
+ "lib/rea/meta_type/type.rb",
70
+ "lib/rea/plugins/active_model.rb",
53
71
  "lib/tasks/cucumber.rake",
54
72
  "lib/tasks/rea_tasks.rake",
55
73
  "lib/tasks/watchr.rake",
@@ -80,7 +98,6 @@ Gem::Specification.new do |s|
80
98
  "spec/dummy/config/initializers/wrap_parameters.rb",
81
99
  "spec/dummy/config/locales/en.yml",
82
100
  "spec/dummy/config/routes.rb",
83
- "spec/dummy/db/development.sqlite3",
84
101
  "spec/dummy/db/schema.rb",
85
102
  "spec/dummy/lib/assets/.gitkeep",
86
103
  "spec/dummy/log/.gitkeep",
@@ -101,6 +118,7 @@ Gem::Specification.new do |s|
101
118
  "spec/rea/dsl/structural_spec.rb",
102
119
  "spec/rea/dsl_spec.rb",
103
120
  "spec/rea/engine_spec.rb",
121
+ "spec/rea/meta_type_spec.rb",
104
122
  "spec/spec_helper.rb"
105
123
  ]
106
124
  s.homepage = "http://github.com/lazing/engine-rea"
data/lib/engine-rea.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rea'
data/lib/rea.rb CHANGED
@@ -2,6 +2,12 @@ require "rea/engine"
2
2
 
3
3
  module Rea
4
4
  autoload :Dsl, 'rea/dsl'
5
-
6
5
  autoload :InstallGenerator, 'generators/rea/install/install_generator'
6
+
7
+ autoload :AspectType, 'rea/aspect_type'
8
+ autoload :MetaType, 'rea/meta_type'
9
+
10
+ module Plugins
11
+ autoload :ActiveModel, 'rea/plugins/active_model'
12
+ end
7
13
  end
@@ -0,0 +1,11 @@
1
+ module Rea
2
+ module AspectType
3
+ autoload :Base, 'rea/aspect_type/base'
4
+ autoload :IdentifierSetup, 'rea/aspect_type/identifier_setup'
5
+ autoload :Description, 'rea/aspect_type/description'
6
+ autoload :DueDateType, 'rea/aspect_type/due_date_type'
7
+ autoload :Classification, 'rea/aspect_type/classification_aspect'
8
+ autoload :ClassificationAspect, 'rea/aspect_type/classification_aspect'
9
+ autoload :MemberType, 'rea/aspect_type/classification_aspect'
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Rea
2
+ module AspectType
3
+ class Base
4
+ def initialize options={}
5
+ options.keys.each { |key| self.instance_variable_set("@#{key}", options[key]) }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,75 @@
1
+ module Rea
2
+ module AspectType
3
+ module Classification
4
+ def self.included base
5
+ base.extend ClassMethods
6
+ base.scope :by_category, lambda { |category_type_name, category_name|
7
+ $field_name = base.rea_ast[:classification][category_type_name.to_sym]
8
+ base.where($field_name.to_sym=>category_name)
9
+ }
10
+ end
11
+
12
+ def is category
13
+ $field_name = self.class.rea_ast[:classification][category.category_type.name.to_sym]
14
+ self.send($field_name).to_sym == category.name.to_sym
15
+ end
16
+
17
+ def is_in category
18
+ field_name = self.class.rea_ast[:classification][category.category_type.name.to_sym]
19
+ $current = category.class.find_by_name(self.send(field_name))
20
+ while($current) do
21
+ return true if $current.name.to_s == category.name.to_s
22
+ $current = $current.parent_category
23
+ end
24
+ return false
25
+ end
26
+
27
+ module CategoryType
28
+ def category *category_names, &block
29
+ options = category_names.extract_options!
30
+ category_names.flatten.each do |name|
31
+ category = self.categories.find_or_create_by_name name, options
32
+ block.call(category) if block_given?
33
+ end
34
+ end
35
+ end
36
+
37
+ module Category
38
+ def category *category_names, &block
39
+ options = category_names.extract_options!
40
+ options = {:category_type_id=>self.category_type_id, :category_id=>self.id}.merge(options)
41
+ category_names.flatten.each do |name|
42
+ category = self.child_categories.find_or_create_by_name name, options
43
+ block.call(category) if block_given?
44
+ end
45
+ end
46
+ end
47
+
48
+ module ClassMethods
49
+ def category_type category_type_name, options={}, &block
50
+ category_type = ::Rea::CategoryType.find_or_create_by_name category_type_name, options
51
+ block.call(category_type) if block_given?
52
+ end
53
+
54
+
55
+ def member name, options={}
56
+ options = { :name=>name.to_s }.merge options
57
+ rea[name] = ::Rea::AspectType::MemberType.new options
58
+ rea_ast[:classification][options[:type]] = name
59
+ end
60
+ end
61
+ end
62
+ class ClassificationAspect < Base
63
+ end
64
+
65
+ class MemberType < Base
66
+ attr_reader :name, :type
67
+
68
+ def category_options
69
+ category_type = ::Rea::CategoryType.find_by_name(self.type.to_s)
70
+ category_type.categories
71
+ end
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,7 @@
1
+ module Rea
2
+ module AspectType
3
+ class Description < Base
4
+ attr_accessor :name, :media
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class Rea::AspectType::DueDateType < Rea::AspectType::Base
2
+
3
+ attr_reader :name, :activation_rule
4
+
5
+ end
@@ -0,0 +1,7 @@
1
+ module Rea
2
+ module AspectType
3
+ class IdentifierSetup < Base
4
+ attr_reader :name, :identifier
5
+ end
6
+ end
7
+ end
data/lib/rea/dsl.rb CHANGED
@@ -7,6 +7,10 @@ module Rea
7
7
 
8
8
  def self.included base
9
9
  base.extend ClassMethods
10
+ base.cattr_reader :rea, :rea_ast
11
+ base.cattr_accessor :type, :fields
12
+ base.class_variable_set "@@rea", {}
13
+ base.class_variable_set "@@rea_ast", {}
10
14
  base.class_eval do
11
15
  include Structural
12
16
  include Behavioral
@@ -6,34 +6,44 @@ module Rea
6
6
  end
7
7
 
8
8
  def create_id_string
9
- self.send("#{self.class.identifier_field}=", Rea::Identifier.find_last_by_name(self.class.identifier).try(:generate))
9
+ id_setup = self.class.rea_ast[:identifier]
10
+ self.send("#{id_setup.name}=", Rea::Identifier.find_last_by_name(id_setup.identifier).try(:generate))
10
11
  end
11
12
 
12
13
  module ClassMethods
13
- def classification name, options={}, &block
14
- precontext = @context
15
- @context = @context.category_types.find_or_create_by_name name, options
14
+
15
+ def classification options={}, &block
16
+ include ::Rea::AspectType::Classification
17
+ rea_ast[:classification] = {}
18
+ Rea::CategoryType.find_or_create_by_name name.to_s, options
16
19
  block.call if block_given?
17
- @context = precontext
18
20
  end
19
21
 
20
- def category *category_names, &block
21
- options = category_names.extract_options!
22
- category_names.flatten.each do |name|
23
- attr_name = @context.is_a?(Rea::Category) ? :child_categories : :categories
24
- precontext = @context
25
- @context = @context.send(attr_name).find_or_create_by_name name, options
26
- block.call if block_given?
27
- @context = precontext
28
- end
29
- end
30
22
 
31
- def identification name, options={}
32
- cattr_accessor :identifier, :identifier_field
33
- self.identifier = name
34
- self.identifier_field = options.delete(:identifier_field) || :sn
23
+ def identification name, identifier
24
+ rea_ast[:identifier] = ::Rea::AspectType::IdentifierSetup.new :name=>name, :identifier=>identifier
35
25
  self.before_create :create_id_string
36
26
  end
27
+
28
+ def description name, media, options={}
29
+ rea[name] = ::Rea::AspectType::Description.new :name=>name, :media=>media
30
+ end
31
+
32
+ def due_date name, options={}
33
+ options = {:name=>name, :activation_rule=>'true'}.merge(options)
34
+ rea[name] = ::Rea::AspectType::DueDateType.new options
35
+ define_method "#{name}_state".to_sym do
36
+ if try(name).nil?
37
+ :disabled
38
+ else
39
+ if send(name) > Time.now
40
+ :incoming
41
+ else
42
+ :expired
43
+ end
44
+ end
45
+ end
46
+ end
37
47
  end
38
48
  end
39
49
  end
@@ -3,68 +3,51 @@ module Rea
3
3
  module Structural
4
4
  def self.included base
5
5
  base.extend ClassMethods
6
+ if base == ActiveRecord::Base
7
+
8
+ else
9
+ base.class_eval do
10
+ include ::Rea::Plugins::ActiveModel
11
+ def initialize options = {}
12
+ options.keys.each do |key|
13
+ instance_variable_set "@#{key}", options[key]
14
+ end
15
+ end
16
+ end
17
+ end
6
18
  end
7
19
 
8
- module ClassMethods
9
-
10
- def def_entity options={}, &block
11
- validates_presence_of :name
12
- block.call if block_given?
13
- end
14
20
 
21
+ module ClassMethods
15
22
 
16
- def item name, options={}, &block
17
- @context = self.find_or_create_by_name name, options
23
+ def acts_as_resource options={}, &block
24
+ include ::Rea::MetaType::Resource
18
25
  block.call if block_given?
19
26
  end
20
27
 
21
- def resource options={}, &block
22
- def_entity options, &block
23
- end
24
-
25
- def event increase=true, options={}, &block
26
- def_entity options, &block
27
- cattr_accessor :increase
28
- self.increase = increase
29
- end
30
-
31
- def increase_event options={}, &block
32
- event true, options, &block
33
- end
34
-
35
- def decrease_event options={}, &block
36
- event false, options, &block
37
- end
38
28
 
39
- def agent options={}, &block
40
- def_entity options, &block
29
+ def acts_as_commitment options={}, &block
30
+ include ::Rea::MetaType::Commitment
31
+ yield
41
32
  end
42
33
 
43
- def grouping options={}, &block
44
- has_many :group_entities, :as=>:entity
45
- has_many :groups, :through=>:group_entities
46
- #group_class.entity_classes << self
34
+ def acts_as_event options={}, &block
35
+ include ::Rea::MetaType::Event
47
36
  block.call if block_given?
48
37
  end
49
38
 
50
- def group_item *group_names, &block
51
- options = group_names.extract_options!
52
- group_names.flatten.each do |name|
53
- @context = Rea::Group.groups(self).find_or_create_by_name(name, :entity_types=>self.name)
54
- block.call if block_given?
55
- end
56
- end
57
-
58
- def entity_type name, options={}, &block
59
- has_many name, options
60
- def_entity options, &block
39
+ def acts_as_agent options={}, &block
40
+ include ::Rea::MetaType::Agent
41
+ yield if block_given?
61
42
  end
62
43
 
63
- def specification name, options={}
64
- belongs_to name, options
44
+ def acts_as_contract options={}
45
+ include ::Rea::MetaType::Contract
46
+ yield if block_given?
65
47
  end
66
48
 
67
49
  end
50
+
68
51
  end
69
52
  end
70
53
  end
@@ -0,0 +1,8 @@
1
+ module Rea
2
+ module MetaType
3
+
4
+ %w{entity resource event agent commitment contract group type schedule}.each do |name|
5
+ autoload name.camelize.to_sym, "rea/meta_type/#{name}"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ module Rea
2
+ module MetaType
3
+ module Agent
4
+ def self.included base
5
+ base.fields = [:name]
6
+ Entity.included base
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ module Rea
2
+ module MetaType
3
+ module Commitment
4
+ def self.included base
5
+ base.fields = [:amount]
6
+ Entity.included base
7
+ base.extend ::Rea::MetaType::Event::ClassMethods
8
+ base.extend ClassMethods
9
+ base.after_save :after_save_commitment
10
+ end
11
+
12
+ def after_save_commitment
13
+ if fulfilled_changed?
14
+ self.class.event_creator.create_event(self)
15
+ end
16
+ end
17
+
18
+ module ClassMethods
19
+
20
+ def event_creator klass, options={}
21
+ cattr_reader :event_creator
22
+ self.class_variable_set "@@event_creator", klass
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ module Rea
2
+ module MetaType
3
+ module Contract
4
+ def self.included base
5
+ base.fields = nil
6
+ Entity.included base
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def clause klass, options={}
12
+ has_many klass.name.tableize.to_sym, {:class_name=>klass.name, :foreign_key=>:contract_id}.merge(options)
13
+ klass.belongs_to :contract, :class_name => self.name
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,50 @@
1
+ module Rea
2
+ module MetaType
3
+ module Entity
4
+ def self.included base
5
+ base.class_eval do
6
+ unless self.ancestors.include? ActiveRecord::Base
7
+ include ::Rea::Plugins::ActiveModel
8
+ attr_accessor *self.fields if base.fields
9
+ end
10
+ validates_presence_of *self.fields if base.fields
11
+ end
12
+ base.extend ClassMethods
13
+ end
14
+
15
+ module ClassMethods
16
+
17
+ def item name, options={}, &block
18
+ if self.ancestors.include?(ActiveRecord::Base)
19
+ @context = self.find_or_create_by_name name, options
20
+ else
21
+ cattr_reader name
22
+ @context = self.new({:name=>name.to_s, :value=>1}.merge(options))
23
+ self.class_variable_set "@@#{name}", @context
24
+ end
25
+ block.call if block_given?
26
+ end
27
+
28
+ def grouping options={}, &block
29
+ has_many :group_entities, :as=>:entity
30
+ has_many :groups, :through=>:group_entities
31
+ #group_class.entity_classes << self
32
+ block.call if block_given?
33
+ end
34
+
35
+ def group_item *group_names, &block
36
+ options = group_names.extract_options!
37
+ group_names.flatten.each do |name|
38
+ @context = Rea::Group.groups(self).find_or_create_by_name(name, :entity_types=>self.name)
39
+ block.call if block_given?
40
+ end
41
+ end
42
+
43
+
44
+ def specification name, options={}
45
+ belongs_to name, options
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,46 @@
1
+ module Rea
2
+ module MetaType
3
+ module Event
4
+ def self.included base
5
+ base.fields = [:amount]
6
+ Entity.included base
7
+ base.extend ClassMethods
8
+ base.extend EventClassMethods
9
+ end
10
+
11
+ module EventClassMethods
12
+ def create_event commitment
13
+ amount = (commitment.fulfilled?) ? commitment.amount : -commitment.amount
14
+ options = {:resource_id=>commitment.resource_id, :amount=>amount}
15
+ options.merge!(
16
+ if commitment.respond_to?(:provider)
17
+ {:provider_id=>commitment.provider_id}
18
+ else
19
+ {:recipient_id=>commitment.recipient_id}
20
+ end
21
+ )
22
+ self.create! options
23
+ end
24
+ end
25
+
26
+ module ClassMethods
27
+ def provider klass, options={}
28
+ define_belongs_to_relation :provider, klass, options
29
+ end
30
+ def recipient klass, options={}
31
+ define_belongs_to_relation :recipient, klass, options
32
+ end
33
+ def resource klass, options={}
34
+ define_belongs_to_relation :resource, klass, options
35
+ end
36
+
37
+ protected
38
+ def define_belongs_to_relation name, klass, options
39
+ belongs_to name, {:class_name=>klass.name}.merge(options)
40
+ validates_presence_of "#{name}_id".to_sym
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+ end
File without changes
@@ -0,0 +1,10 @@
1
+ module Rea
2
+ module MetaType
3
+ module Resource
4
+ def self.included base
5
+ base.fields = [:name, :value]
6
+ Entity.included base
7
+ end
8
+ end
9
+ end
10
+ end
File without changes
File without changes
@@ -0,0 +1,18 @@
1
+ module Rea
2
+ module Plugins
3
+ module ActiveModel
4
+ extend ActiveSupport::Concern
5
+
6
+ include ::ActiveModel::Conversion
7
+ include ::ActiveModel::Validations
8
+ include ::ActiveModel::Serialization
9
+ include ::ActiveModel::Serializers::Xml
10
+ include ::ActiveModel::Serializers::JSON
11
+
12
+ included do
13
+ extend ::ActiveModel::Naming
14
+ extend ::ActiveModel::Translation
15
+ end
16
+ end
17
+ end
18
+ end
@@ -6,23 +6,23 @@ describe Rea::Dsl::Behavioral do
6
6
  with_model :entity do
7
7
  table do |t|
8
8
  t.string :name
9
+ t.string :value
9
10
  t.string :sn
10
11
  end
11
12
  model do
12
- resource do
13
- identification :entity_sn
13
+ acts_as_resource do
14
+ identification :sn, :entity_sn
14
15
  end
15
16
  end
16
17
  end
17
18
 
18
19
  context :sematics do
19
- subject { Entity }
20
- its(:identifier) { should == :entity_sn }
21
- its(:identifier_field) { should == :sn }
20
+ subject { Entity.rea_ast }
21
+ its([:identifier]) { should be_a_kind_of Rea::AspectType::IdentifierSetup }
22
22
  end
23
23
 
24
24
  context :model do
25
- subject { Entity.create :name=>:entity }
25
+ subject { Entity.create :name=>:entity, :value=>1 }
26
26
 
27
27
  before(:all) { Rea::Identifier.create! :name=>:entity_sn, :id_rule=>'#{"%010d" % last_value}' }
28
28
 
@@ -38,44 +38,112 @@ describe Rea::Dsl::Behavioral do
38
38
  with_model :entity do
39
39
  table do |t|
40
40
  t.string :name
41
+ t.string :value
42
+ t.string :category
41
43
  end
42
44
  model do
43
- resource do
44
- grouping do
45
- group_item :group_one do
46
- classification 'category_type_one'
47
- classification 'category_type_two', :automatic=>true, :system=>true do
48
- category :category_one, :category_two
49
- category :category_tree do
50
- category :category_node_1, :category_node_2, :category_node_3
51
- end
45
+ acts_as_resource do
46
+ classification do
47
+ category_type 'category_type_one' do |ct|
48
+ ct.category :cate_1 do |c|
49
+ c.category :cate_2, :cate_3
50
+ end
51
+ end
52
+ category_type 'category_type_two', :automatic=>true, :system=>true do |ct|
53
+ ct.category :category_one, :category_two
54
+ ct.category :category_tree do |c|
55
+ c.category :category_node_1, :category_node_2, :category_node_3
52
56
  end
53
57
  end
54
58
  end
59
+ member :category, :type=>:category_type_one
55
60
  end
56
61
  end
57
62
  end
58
63
 
59
- context :category_type_defaults do
60
- subject { Rea::CategoryType.find_by_name 'category_type_one' }
64
+ context :sematics do
65
+
66
+ context :category_type_defaults do
67
+ subject { Rea::CategoryType.find_by_name 'category_type_one' }
68
+
69
+ it { should_not be_nil }
70
+ it { should_not be_system }
71
+ it { should_not be_multiple }
72
+ it { should_not be_automatic }
73
+ end
74
+
75
+ context :category_type_two do
76
+ subject { Rea::CategoryType.find_by_name 'category_type_two' }
77
+
78
+ it { should_not be_nil }
79
+ its(:categories) { should have(6).items }
80
+ context :category_tree do
81
+ subject { Rea::Category.find_by_name('category_tree').child_categories }
82
+ it { should have(3).items }
83
+ end
84
+ end
61
85
 
62
- it { should_not be_nil }
63
- it { should_not be_system }
64
- it { should_not be_multiple }
65
- it { should_not be_automatic }
86
+ context :rea do
87
+ subject { Entity.rea }
88
+ its([:category]) { should be_a_kind_of(Rea::AspectType::MemberType) }
89
+ end
90
+ context :member_field do
91
+ subject { Entity.rea[:category] }
92
+ its(:category_options) { should have(3).items }
93
+ end
66
94
  end
95
+ context :model do
96
+ context :entity do
97
+ context :methods do
98
+ let(:cate_3) { Rea::Category.find_by_name :cate_3 }
99
+ let(:cate_1) { Rea::Category.find_by_name :cate_1 }
100
+ subject { Entity.create :name=>:name, :value=>1, :category=>:cate_3 }
101
+ it { subject.is(cate_3).should be_true }
102
+ it { subject.is_in(cate_1).should be_true }
103
+ end
104
+ end
105
+ end
106
+ end
67
107
 
68
- context :category_type_two do
69
- subject { Rea::CategoryType.find_by_name 'category_type_two' }
108
+ context :description do
70
109
 
71
- it { should_not be_nil }
72
- its(:categories) { should have(3).items }
73
- context :category_tree do
74
- subject { Rea::Category.find_by_name('category_tree').child_categories }
75
- it { should have(3).items }
110
+ with_model :entity do
111
+ table do |t|
76
112
  end
113
+ model do
114
+ acts_as_resource do
115
+ description :text, :text
116
+ description :markdown, :md
117
+ end
118
+ end
119
+ end
77
120
 
121
+ subject { Entity.rea }
122
+ its([:text]) { should be_a_kind_of(Rea::AspectType::Description) }
123
+ end
124
+
125
+ context :due_date do
126
+ with_model :entity do
127
+ table do |t|
128
+ t.datetime :date_one
129
+ t.datetime :date_two
130
+ end
131
+ model do
132
+ acts_as_resource do
133
+ due_date :date_one
134
+ due_date :date_two, :activation_rule=>'date_one.nil?'
135
+ end
136
+ end
78
137
  end
79
138
 
139
+ context :sematics do
140
+ subject { Entity.rea }
141
+ its([:date_one]) { should be_a_kind_of(::Rea::AspectType::DueDateType) }
142
+ end
143
+ context :model do
144
+ subject { Entity.new :date_one=>1.day.ago, :date_two=>nil }
145
+ its(:date_one_state) { should == :expired }
146
+ its(:date_two_state) { should == :disabled }
147
+ end
80
148
  end
81
149
  end
@@ -1,112 +1,270 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Rea::Dsl::Structural do
4
-
5
- context :resource do
6
- with_model :resource do
7
- table do |t|
8
- t.string :name
9
- end
10
- model do
11
- resource do
12
- end
4
+ shared_examples "entities" do |attrs, defaults|
5
+ context :definations do
6
+ let!(:entity) { entity_class.new defaults }
7
+ subject { entity_class }
8
+ attrs.each do |attr|
9
+ its(:public_instance_methods) { should include attr }
13
10
  end
14
11
  end
15
-
16
- subject { Resource.new }
17
- context :validation do
18
- it { subject.respond_to?(:name).should be_true }
19
- it { subject.should_not be_valid }
12
+ context :validations do
13
+ context :valid do
14
+ subject { (entity_class).new defaults }
15
+ after(:each) { pp subject.errors unless subject.valid? }
16
+ it { should be_valid }
17
+ end
18
+ context :invalid do
19
+ subject { (entity_class).new }
20
+ it { should_not be_valid }
21
+ end
20
22
  end
21
23
  end
22
24
 
23
- context :event do
24
- with_model :event do
25
+ def self.create_entity_model name, columns = [:name, :value], &block
26
+ with_model name do
25
27
  table do |t|
26
- t.string :name
27
- end
28
- model do
29
- event
28
+ columns.each do |c| t.string c end
30
29
  end
30
+ model &block
31
31
  end
32
- subject { Event.new }
33
- it { subject.respond_to?(:name).should be_true }
32
+ let!(:entity_class) { name.to_s.camelize.constantize }
34
33
  end
35
34
 
36
- context :agent do
37
- with_model :agent do
38
- table do |t|
39
- t.string :name
35
+
36
+ context :acts_as_resource do
37
+ context :active_record do
38
+ with_model :resource do
39
+ table do |t|
40
+ t.string :name
41
+ t.decimal :value
42
+ end
43
+ model do
44
+ acts_as_resource
45
+ end
40
46
  end
41
- model do
42
- agent
47
+ let!(:entity_class) { Resource }
48
+ include_examples "entities", [:name, :value], :name=>:name, :value=>1
49
+ end
50
+
51
+ context :simple_class do
52
+ class SimpleResource
53
+ include Rea::Dsl
54
+ acts_as_resource do
55
+ item :rmb, :id=>1, :value=>1
56
+ item :usd, :id=>2, :value=>6.78
57
+ end
58
+ end
59
+
60
+ entity_class = SimpleResource
61
+ let!(:entity_class) { entity_class }
62
+ include_examples "entities", [:name, :value], :name=>:name, :value=>1
63
+ context :nested_items do
64
+ subject { entity_class }
65
+ its("rmb.value") { should == 1 }
66
+ its("rmb.name") { should == "rmb" }
67
+ its("usd.value") { should == 6.78 }
43
68
  end
44
69
  end
45
- subject { Agent.new }
46
- it { subject.respond_to?(:name).should be_true }
47
70
  end
48
71
 
49
- context :entity do
72
+ context :acts_as_agent do
73
+ context :active_record do
74
+ create_entity_model(:agent, [:name]) do acts_as_agent end
75
+ include_examples "entities", [:name], :name=>:name
76
+ end
50
77
 
51
- with_model :entity do
52
- table do |t|
53
- t.string :name
54
- end
55
- model do
56
- resource do
57
- item :name_one
58
- item :name_two
78
+ context :simple_class do
79
+ class SimpleAgent
80
+ include Rea::Dsl
81
+ acts_as_agent do
82
+ item :facebook, :id=>1
83
+ item :google, :id=>2
59
84
  end
60
85
  end
61
- end
62
- context :item do
63
- it :have_2_items do
64
- Entity.count.should == 2
86
+ entity_class = SimpleAgent
87
+ let!(:entity_class) { entity_class}
88
+ include_examples "entities", [:name], :name=>:name
89
+ context :nested_items do
90
+ subject { entity_class }
91
+ its("facebook.name") { should == "facebook" }
65
92
  end
66
93
  end
94
+
67
95
  end
68
96
 
69
- context :entity_type do
70
- with_model :entity_type do
71
- table do |t|
72
- t.string :name
97
+ context :acts_as_event do
98
+ context :active_record do
99
+ with_model :resource do
100
+ table do |t|
101
+ t.string :name
102
+ t.decimal :value
103
+ end
104
+ model do
105
+ acts_as_resource
106
+ end
73
107
  end
74
- model do
75
- entity_type :entities
108
+ with_model :agent do
109
+ table do |t|
110
+ t.string :name
111
+ end
112
+ model do
113
+ acts_as_agent
114
+ end
115
+ end
116
+ with_model :increment_event do
117
+ table do |t|
118
+ t.references :resource
119
+ t.references :provider
120
+ t.decimal :amount
121
+ t.timestamps
122
+ end
123
+ model do
124
+ acts_as_event do
125
+ resource Resource
126
+ provider Agent
127
+ end
128
+ end
76
129
  end
130
+ let!(:entity_class) { IncrementEvent }
131
+ include_examples "entities", [:resource, :amount, :provider ], {:resource_id=>1,:provider_id=>1,:amount=>1}
77
132
  end
78
133
 
79
- with_model :entity do
80
- table do |t|
81
- t.string :name
82
- t.references :entity_type
134
+ end
135
+ context :acts_as_increment_commitment do
136
+ context :active_record do
137
+ with_model :resource do
138
+ table do |t|
139
+ t.string :name
140
+ t.decimal :value
141
+ end
142
+ model do
143
+ acts_as_resource
144
+ end
83
145
  end
84
- model do
85
- resource do
86
- specification :entity_type
146
+ with_model :agent do
147
+ table do |t|
148
+ t.string :name
149
+ end
150
+ model do
151
+ acts_as_agent
152
+ end
153
+ end
154
+ with_model :increment_event do
155
+ table do |t|
156
+ t.references :resource
157
+ t.references :provider
158
+ t.decimal :amount
159
+ t.timestamps
160
+ end
161
+ model do
162
+ acts_as_event do
163
+ resource Resource
164
+ provider Agent
165
+ end
87
166
  end
88
167
  end
89
- end
90
168
 
91
- context :entity do
92
- subject { Entity.reflect_on_association(:entity_type) }
169
+ with_model :increment_commitment do
170
+ table do |t|
171
+ t.references :resource
172
+ t.references :provider
173
+ t.decimal :amount
174
+ t.boolean :fulfilled, :default=>false
175
+ t.timestamps
176
+ end
177
+ model do
178
+ acts_as_commitment do
179
+ resource Resource
180
+ provider Agent
181
+ event_creator IncrementEvent
182
+ end
183
+ end
184
+ end
185
+ let!(:entity_class) { IncrementCommitment }
186
+ include_examples "entities", [:resource, :amount, :provider ], {:resource_id=>1,:provider_id=>1,:amount=>1}
93
187
 
94
- it { should_not be_nil }
95
- its(:macro) { should == :belongs_to }
96
- end
188
+ context :fulfill do
189
+ subject { IncrementCommitment }
190
+ its(:event_creator) { should == IncrementEvent }
191
+ end
97
192
 
98
- context :entity_type do
99
- subject { EntityType.reflect_on_association(:entities) }
100
- it { should_not be_nil }
101
- its(:macro) { should == :has_many }
193
+ context :callback do
194
+ subject { IncrementCommitment.new :resource_id=>1, :provider_id=>1, :amount=>1, :fulfilled=>true }
195
+ it :should_create_event do
196
+ expect {
197
+ subject.save
198
+ }.to change {IncrementEvent.count}
199
+ end
200
+ it :event_sum_amount_should_plus_when_fulfill do
201
+ expect {
202
+ subject.save
203
+ }.to change{IncrementEvent.sum(:amount)}.by(1)
204
+ end
205
+ it :event_sum_amount_should_minus_when_not_fulfill do
206
+ subject.save
207
+ subject.fulfilled = false
208
+ expect {
209
+ subject.save
210
+ }.to change{IncrementEvent.sum(:amount)}.by(-1)
211
+ end
212
+ end
102
213
  end
214
+ end
103
215
 
104
- context :entity_create do
105
- let!(:entity_type) { EntityType.create :name=>:type }
106
- let!(:entity) { entity_type.entities.create :name=>:type }
107
-
108
- subject { entity_type }
109
- its(:entities) { should have(1).items }
216
+ context :acts_as_contract do
217
+ context :normal do
218
+ with_model :increment_commitment do
219
+ table do |t|
220
+ t.references :provider
221
+ t.references :resource
222
+ t.references :contract
223
+ t.decimal :amount
224
+ t.boolean :fulfilled
225
+ end
226
+ model do
227
+ acts_as_commitment do
228
+ end
229
+ end
230
+ end
231
+ with_model :decrement_commitment do
232
+ table do |t|
233
+ t.references :contract
234
+ end
235
+ model do
236
+ acts_as_commitment do
237
+ end
238
+ end
239
+ end
240
+ with_model :order do
241
+ table do |t|
242
+ end
243
+ model do
244
+ acts_as_contract do
245
+ clause IncrementCommitment
246
+ clause DecrementCommitment
247
+ end
248
+ end
249
+ end
250
+ context :sematics do
251
+ context :contract do
252
+ subject { Order }
253
+ its(:public_instance_methods) { should include :increment_commitments }
254
+ its(:public_instance_methods) { should include :decrement_commitments }
255
+ end
256
+ context :commitment do
257
+ subject { IncrementCommitment }
258
+ its(:public_instance_methods) { should include :contract }
259
+ end
260
+ end
261
+ context :model do
262
+ subject { Order.create }
263
+ it :could_add_increment_commitment do
264
+ expect { subject.increment_commitments.create :provider_id=>1, :resource_id=>1, :amount=>10
265
+ }.to change{IncrementCommitment.count}
266
+ end
267
+ end
110
268
  end
111
269
  end
112
270
 
@@ -116,7 +274,7 @@ describe Rea::Dsl::Structural do
116
274
  t.string :name
117
275
  end
118
276
  model do
119
- resource do
277
+ acts_as_resource do
120
278
  grouping do
121
279
  group_item :group_one, :group_two
122
280
  group_item :group_three
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rea::MetaType do
4
+
5
+ context :autoload do
6
+
7
+ subject { described_class }
8
+
9
+ it { subject.autoload?(:Event).should be_true }
10
+ end
11
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: engine-rea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-06 00:00:00.000000000 Z
12
+ date: 2012-06-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -301,13 +301,31 @@ files:
301
301
  - db/migrate/20120605030708_create_rea_group_entities.rb
302
302
  - db/migrate/20120605082028_create_rea_identifiers.rb
303
303
  - engine-rea.gemspec
304
+ - lib/engine-rea.rb
304
305
  - lib/generators/rea/install/USAGE
305
306
  - lib/generators/rea/install/install_generator.rb
306
307
  - lib/rea.rb
308
+ - lib/rea/aspect_type.rb
309
+ - lib/rea/aspect_type/base.rb
310
+ - lib/rea/aspect_type/classification_aspect.rb
311
+ - lib/rea/aspect_type/description.rb
312
+ - lib/rea/aspect_type/due_date_type.rb
313
+ - lib/rea/aspect_type/identifier_setup.rb
307
314
  - lib/rea/dsl.rb
308
315
  - lib/rea/dsl/behavioral.rb
309
316
  - lib/rea/dsl/structural.rb
310
317
  - lib/rea/engine.rb
318
+ - lib/rea/meta_type.rb
319
+ - lib/rea/meta_type/agent.rb
320
+ - lib/rea/meta_type/commitment.rb
321
+ - lib/rea/meta_type/contract.rb
322
+ - lib/rea/meta_type/entity.rb
323
+ - lib/rea/meta_type/event.rb
324
+ - lib/rea/meta_type/group.rb
325
+ - lib/rea/meta_type/resource.rb
326
+ - lib/rea/meta_type/schedule.rb
327
+ - lib/rea/meta_type/type.rb
328
+ - lib/rea/plugins/active_model.rb
311
329
  - lib/tasks/cucumber.rake
312
330
  - lib/tasks/rea_tasks.rake
313
331
  - lib/tasks/watchr.rake
@@ -338,7 +356,6 @@ files:
338
356
  - spec/dummy/config/initializers/wrap_parameters.rb
339
357
  - spec/dummy/config/locales/en.yml
340
358
  - spec/dummy/config/routes.rb
341
- - spec/dummy/db/development.sqlite3
342
359
  - spec/dummy/db/schema.rb
343
360
  - spec/dummy/lib/assets/.gitkeep
344
361
  - spec/dummy/log/.gitkeep
@@ -359,6 +376,7 @@ files:
359
376
  - spec/rea/dsl/structural_spec.rb
360
377
  - spec/rea/dsl_spec.rb
361
378
  - spec/rea/engine_spec.rb
379
+ - spec/rea/meta_type_spec.rb
362
380
  - spec/spec_helper.rb
363
381
  homepage: http://github.com/lazing/engine-rea
364
382
  licenses:
@@ -375,7 +393,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
375
393
  version: '0'
376
394
  segments:
377
395
  - 0
378
- hash: -984343217
396
+ hash: -104373165
379
397
  required_rubygems_version: !ruby/object:Gem::Requirement
380
398
  none: false
381
399
  requirements:
Binary file