ygg 0.0.2 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ Feature: Ygg Domain Specific Language
2
+ In order to access ygg features easily
3
+ As a Ygg user
4
+ I want to have a nice DSL
5
+
6
+ Background: All that from the other features
7
+ Given the class User has the field :name
8
+ And extends Record
9
+ And the class Account has the field :amount
10
+ And the class Account has the field :currency
11
+ And extends Record
12
+ And I have the file "emulations/samples/user.ygg"
13
+
14
+ Scenario: Data on session closed
15
+ When I load the file
16
+ And I ask User for records
17
+ Then I should get an user named "Xavier Via"
18
+
19
+ Scenario: Giving path & identifier
20
+ Given the path "emulations/samples"
21
+ And the identifier :user
22
+ When I call ygg with those arguments
23
+ And I ask User for records
24
+ Then I should get an user named "Xavier Via"
@@ -0,0 +1,17 @@
1
+ Feature: Event managing
2
+ In order to recall data from past interactions
3
+ As an ygg user
4
+ I want to manage an event log
5
+
6
+ Background: Setting up the enviroment
7
+ Given I have the base path "emulations/samples"
8
+ And the class User has the field :name
9
+
10
+ Scenario: Accessing the last event
11
+ Given the file "emulations/samples/event.ygg" contains:
12
+ """
13
+ - !ruby/object:YggDemo::User
14
+ name: John Doe
15
+ """
16
+ When I interact with the resource :event
17
+ Then I should see that the last event loaded some User
@@ -0,0 +1,40 @@
1
+ Feature: Load and save a simple record from a file
2
+ In order to check Ygg's ability to manage record
3
+ As a Ygg developer
4
+ I want to load and save simple YAML records
5
+
6
+ Scenario: Load a basic User record
7
+ Given the class User has the field :name
8
+ And the file "emulations/samples/user.ygg" contains:
9
+ """
10
+ - !ruby/object:YggDemo::User
11
+ name: Xavier Via
12
+ """
13
+ When I load the file and get the records
14
+ Then the first record should be a User
15
+ And it should have the name "Xavier Via"
16
+
17
+ @saves
18
+ Scenario: Save a basic User record
19
+ Given the class User has the field :name
20
+ And I have a user "Catalina" in an array
21
+ When I load the file "emulations/samples/saving.ygg" and add the array to the data
22
+ Then the file should contain:
23
+ """
24
+ - !ruby/object:YggDemo::User
25
+ name: Catalina
26
+ """
27
+
28
+ Scenario: Set a base folder and load files with symbols
29
+ Given I have the file "emulations/samples/user.ygg"
30
+ When I set "emulations/samples" as base folder
31
+ And I load :user
32
+ Then I should get non empty data
33
+
34
+ Scenario: No block given, no data saved
35
+ Given the class User has the field :name
36
+ And I have the file "emulations/samples/user.ygg"
37
+ And I get its modified date
38
+ When I load it without block
39
+ Then I should get non empty data
40
+ And the file should not have been modified
@@ -0,0 +1,8 @@
1
+ Given /^extends Record$/ do
2
+ @the_class.extend Ygg::Record
3
+ end
4
+
5
+ When /^I load the file and ask (.+?) for records$/ do |type|
6
+ @the_class = YggDemo.const_get type
7
+ @the_records = @the_class.from_ygg
8
+ end
@@ -0,0 +1,20 @@
1
+ Given /^the path "(.+?)"$/ do |path|
2
+ @argument_path = File.dirname(File.dirname(File.dirname(__FILE__)))
3
+ @argument_path += "/#{path}"
4
+ end
5
+
6
+ Given /^the identifier :(.+?)$/ do |identifier_name|
7
+ @the_identifier = identifier_name.to_sym
8
+ end
9
+
10
+ When /^I call ygg with those arguments$/ do
11
+ ygg @argument_path, @the_identifier
12
+ end
13
+
14
+ When /^I load the file$/ do
15
+ ygg @the_path
16
+ end
17
+
18
+ When /^I ask (.+?) for records$/ do |type|
19
+ @the_records = YggDemo.const_get(type).from_ygg
20
+ end
@@ -0,0 +1,12 @@
1
+ Given /^I have the base path "(.+?)"$/ do |path|
2
+ Ygg.base_dir = File.dirname(File.dirname(File.dirname(__FILE__))) +
3
+ "/#{path}"
4
+ end
5
+
6
+ When /^I interact with the resource :(.+?)$/ do |resource_name|
7
+ ygg resource_name.to_sym
8
+ end
9
+
10
+ Then /^I should see that the last event loaded some (.+?)$/ do |what|
11
+ ygg.events.last.should have_loaded_some(YggDemo.const_get(what))
12
+ end
@@ -0,0 +1,104 @@
1
+ module YggDemo
2
+ end
3
+
4
+ # Given
5
+ Given /the class (.+?) has the field :(.+?)$/ do |class_name, field_name|
6
+ if YggDemo.const_defined? class_name
7
+ @the_class = YggDemo.const_get class_name
8
+ else
9
+ @the_class = YggDemo.const_set class_name, Class.new
10
+ end
11
+
12
+ @the_class.send :attr_accessor, field_name.to_sym
13
+ end
14
+
15
+ Given /the file "(.+?)" contains:/ do |path, content|
16
+ base_path = File.dirname(File.dirname(File.dirname(__FILE__)))
17
+ @the_path = "#{base_path}/#{path}"
18
+ @the_content = File.read @the_path
19
+ @the_content.should include(content)
20
+ end
21
+
22
+ Given /I have a user "(.+?)"/ do |user_name|
23
+ @the_user = YggDemo::User.new
24
+ @the_user.name = user_name
25
+ end
26
+
27
+ Given /^I have the file "(.+?)"$/ do |path|
28
+ base_path = File.dirname(File.dirname(File.dirname(__FILE__)))
29
+ @the_path = "#{base_path}/#{path}"
30
+ File.should exist(@the_path)
31
+ end
32
+
33
+ Given /^I get its modified date$/ do
34
+ @last_modification_time = File.new(@the_path).mtime
35
+ end
36
+
37
+ # When
38
+ When /I load the file and get the records/ do
39
+ @the_records = nil
40
+ ygg @the_path do
41
+ @the_records = records
42
+ end
43
+ end
44
+
45
+ When /^I load the file and request for objects of type (.+?)$/ do |type|
46
+ @the_records = nil
47
+ ygg @the_path do
48
+ @the_records = records.of_type YggDemo.const_get(type)
49
+ end
50
+ end
51
+
52
+ When /I load the file "(.+?)" and add the array to the data$/ do |file_name|
53
+ base_path = File.dirname(File.dirname(File.dirname(__FILE__)))
54
+ @the_path = "#{base_path}/#{file_name}"
55
+ ygg @the_path do
56
+ add @the_user
57
+ end
58
+ end
59
+
60
+ When /I set "(.+?)" as base folder/ do |path|
61
+ base_path = File.dirname(File.dirname(File.dirname(__FILE__)))
62
+ @base_dir = "#{base_path}/#{path}"
63
+ Ygg.base_dir = @base_dir
64
+ end
65
+
66
+ When /^I load :([a-z]+?)$/ do |file|
67
+ @the_data = nil
68
+ ygg file.to_sym do
69
+ @the_data = records
70
+ end
71
+ end
72
+
73
+ When /^I load it without block$/ do
74
+ @the_data = ygg @the_path
75
+ end
76
+
77
+ # Them
78
+ Then /the first record should be a (.+?)$/ do |type|
79
+ @first_record = @the_records.first
80
+ @first_record.should be_a(YggDemo.const_get(type))
81
+ end
82
+
83
+ Then /it should have the (.+?) "(.+?)"/ do |field_name, value|
84
+ @first_record.send(field_name.to_sym).should == value
85
+ end
86
+
87
+ Then /the file should contain:/ do |content|
88
+ File.should exist(@the_path)
89
+ @the_content = File.read @the_path
90
+ @the_content.should include(content)
91
+ end
92
+
93
+ Then /^I should get non empty data$/ do
94
+ @the_data.should_not be_empty
95
+ end
96
+
97
+ Then /^the file should not have been modified$/ do
98
+ @current_modification_time = File.new(@the_path).mtime
99
+ @current_modification_time.should == @last_modification_time
100
+ end
101
+
102
+ Then /^I should get an user named "(.+?)"$/ do |user_name|
103
+ @the_records.first.name.should == user_name
104
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH << File.expand_path("../../../lib", __FILE__)
2
+ require "ygg"
@@ -0,0 +1,3 @@
1
+ After "@saves" do
2
+ File.unlink @the_path
3
+ end
data/lib/ygg.rb CHANGED
@@ -1,5 +1,99 @@
1
- require "ygg/base"
1
+ require "yaml"
2
+ require "metafun/delegator"
2
3
 
3
- include Ygg::Delegator
4
+ # Its time to start over. Bit by bit. Comment everything until
5
+ # features and specs are supplied
4
6
 
5
- delegate Ygg, :save, :data, :load
7
+ require "ygg/databundle"
8
+ require "ygg/session"
9
+ require "ygg/record"
10
+ require "ygg/exceptions"
11
+
12
+ module Ygg
13
+ def self.reset
14
+ @@base_dir = "."
15
+ @@sessions = []
16
+ end
17
+
18
+ reset
19
+
20
+ def self.path_to( source )
21
+ if source.is_a? Symbol
22
+ return "#{@@base_dir}/#{source}.ygg"
23
+ else
24
+ return source
25
+ end
26
+ end
27
+
28
+ def self.transaction( source, &block )
29
+ if not block and not File.exist?(path_to(source))
30
+ raise UnavailableResourceException,
31
+ "No resource was found in #{path_to(source)}"
32
+ end
33
+
34
+ @@sessions << Session.new(path_to(source))
35
+
36
+ if block
37
+ @@within_block = true
38
+ yield block
39
+ @@within_block = nil
40
+ @@sessions.last.shutdown
41
+ end
42
+ return @@sessions.last.records
43
+ end
44
+
45
+ def self.ygg(*args, &block)
46
+ return Ygg if args.empty?
47
+
48
+ self.base_dir = args.shift if args.length > 1
49
+ source = args.shift
50
+
51
+ transaction(source, &block)
52
+ end
53
+
54
+ def self.add(*resources)
55
+ raise ArgumentError if resources.empty?
56
+
57
+ begin
58
+ event = events.last
59
+ resources.each do |resource|
60
+ event.records << resource
61
+ end
62
+ rescue NoInteractionDoneException => e
63
+ raise UnavailableResourceException, "No resource was loaded, impossible to add the object"
64
+ end
65
+ end
66
+
67
+ def self.records
68
+ events.last.records
69
+ end
70
+
71
+ def self.base_dir=(dir)
72
+ @@base_dir = dir
73
+ end
74
+
75
+ def self.base_dir
76
+ @@base_dir
77
+ end
78
+
79
+ def self.events
80
+ raise NoInteractionDoneException, "No events to load in the log." if @@sessions.empty?
81
+ @@sessions
82
+ end
83
+
84
+ def self.resource(*args)
85
+ if args.empty?
86
+ raise OutOfBlockException, "The resource is not available outside an ygg block." unless @@within_block
87
+ events.last
88
+ else
89
+ case args[0]
90
+ when :path
91
+ events.last.source
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ extend Metafun::Delegator
98
+
99
+ delegate Ygg, :ygg, :records, :add
@@ -0,0 +1,63 @@
1
+ module Ygg
2
+ DEFAULT_SOURCE = "your_tree.ygg"
3
+
4
+ class Base
5
+ @@source = Ygg::DEFAULT_SOURCE
6
+ @@data = {}
7
+
8
+ def self.load(source, &block)
9
+ Base.assign_source source if source
10
+ Base.assign_data if File.exists? @@source
11
+
12
+ if block; yield; self.save; self.close; end
13
+ end
14
+
15
+ def self.assign_source(source)
16
+ if source.is_a? Symbol then @@source = "#{source}.ygg"
17
+ else @@source = source
18
+ end
19
+
20
+ def self.assign_data
21
+ @@data = YAML.load_file @@source
22
+
23
+ # Clarify!
24
+ @@data.each do |key, model|
25
+ model.each do |resource|
26
+ resource.loading! if resource.respond_to? :loading!
27
+ end if model.kind_of? Array
28
+ end
29
+ end
30
+
31
+ def self.save
32
+ Base.finalize
33
+
34
+ Base.write
35
+ end
36
+
37
+ def self.finalize
38
+ @@data.each do |key, model|
39
+ model.each do |resource|
40
+ resource._finalize! if resource.respond_to? :_finalize!
41
+ end if model.kind_of? Array
42
+ end
43
+ end
44
+
45
+ def self.data
46
+ @@data
47
+ end
48
+
49
+ def self.close
50
+ @@data = nil
51
+ end
52
+
53
+ def self.write
54
+ File.open @@source, "w" do |file|
55
+ file.write YAML.dump(@@data)
56
+ end
57
+ end
58
+ end
59
+
60
+ def self.ygg(source = nil, &block)
61
+ Base.load source, block
62
+ end
63
+ end
@@ -0,0 +1,31 @@
1
+ module Ygg
2
+ class Branch < Array
3
+ def method_missing(x, *args)
4
+ if matches = x.to_s.match(/^sort_by_(.+)$/)
5
+ key = matches[1].to_sym
6
+ self.sort_by { |x| x.send(key) }
7
+
8
+ elsif matches = x.to_s.match(/^by_(.+)$/) # Extend with regexps
9
+ key = matches[1].to_sym
10
+
11
+ if to_find = args.shift
12
+ result = Branch.new
13
+ self.each do |res|
14
+ if res.respond_to? key
15
+ datus = res.send key
16
+ result << res if datus == to_find
17
+ end
18
+ end
19
+ return Branch.new if result.length == 0
20
+ return result[0] if result.length == 1
21
+ return result
22
+
23
+ else
24
+ self.send(:"sort_by_#{key}")[0] unless empty?
25
+ end
26
+
27
+ return Branch.new
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Ygg
2
+ class InvalidInitializor < RuntimeError; end
3
+ end