From b414b1c26dff5d9f159bf8e53918d8497b1bf720 Mon Sep 17 00:00:00 2001 From: Zhenya Gusev <45536778+zhenyagusev@users.noreply.github.com> Date: Fri, 11 Feb 2022 10:21:51 +0300 Subject: [PATCH 1/2] =?UTF-8?q?Box.Name=20=E2=86=92=20NameGlobally=20and?= =?UTF-8?q?=20NameLocally?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README-ru.md | 3 +- README.md | 3 +- src/BookFx.Tests/BoxTests.cs | 6 +- .../Calculation/MinDimensionCalcTests.cs | 4 +- .../Calculation/PlacementCalcTests.cs | 4 +- .../Calculation/ProtoBankTests.cs | 4 +- .../Calculation/ProtoCalcTests.cs | 6 +- src/BookFx.Tests/Renders/BookRenderTests.cs | 4 +- .../Renders/BoxGlobalNameRenderTests.cs | 53 ++++++++++++++++++ .../Renders/BoxLocalNameRenderTests.cs | 53 ++++++++++++++++++ .../Renders/BoxNameRenderTests.cs | 55 ------------------- .../Validation/BookValidatorTests.cs | 16 +++--- .../Validation/BoxValidatorTests.cs | 10 ++-- .../Validation/SheetValidatorTests.cs | 20 +++++++ src/BookFx.Tests/ValueBoxTests.cs | 4 +- src/BookFx.Usage/S1Table.cs | 2 +- src/BookFx.Usage/S2Style.cs | 8 +-- src/BookFx/Box.cs | 16 +++++- src/BookFx/ColBox.cs | 12 +++- src/BookFx/Cores/BoxCore.cs | 29 +++++++--- src/BookFx/Errors.cs | 26 +++++++-- src/BookFx/ProtoBox.cs | 12 +++- ...oxNameRender.cs => BoxGlobalNameRender.cs} | 8 +-- src/BookFx/Renders/BoxLocalNameRender.cs | 24 ++++++++ src/BookFx/Renders/BoxRender.cs | 3 +- src/BookFx/RowBox.cs | 12 +++- src/BookFx/StackBox.cs | 12 +++- src/BookFx/Validation/BookValidator.cs | 8 +-- src/BookFx/Validation/BoxValidator.cs | 24 ++++---- src/BookFx/Validation/SheetValidator.cs | 11 ++++ src/BookFx/ValueBox.cs | 11 +++- 31 files changed, 333 insertions(+), 130 deletions(-) create mode 100644 src/BookFx.Tests/Renders/BoxGlobalNameRenderTests.cs create mode 100644 src/BookFx.Tests/Renders/BoxLocalNameRenderTests.cs delete mode 100644 src/BookFx.Tests/Renders/BoxNameRenderTests.cs rename src/BookFx/Renders/{BoxNameRender.cs => BoxGlobalNameRender.cs} (67%) create mode 100644 src/BookFx/Renders/BoxLocalNameRender.cs diff --git a/README-ru.md b/README-ru.md index 0acf90e..ec3fda4 100644 --- a/README-ru.md +++ b/README-ru.md @@ -324,7 +324,8 @@ Make.Sheet("New Sheet Name", protoBook, "Prototype Sheet Name"); - `Sheet.Scale` - задать масштаб - `Sheet.ToBook` - создать `Book` с одним листом - `Box` - box любого вида - - `Box.Name` - задать имя области + - `Box.NameGlobally` - присвоить диапазону имя области книги + - `Box.NameLocally` - присвоить диапазону имя области листа - `Box.AutoSpan` - включить режим `AutoSpan` для строк и колонок - `Box.AutoSpanRows` - включить режим `AutoSpan` для строк - `Box.AutoSpanCols` - включить режим `AutoSpan` для колонок diff --git a/README.md b/README.md index 425bde8..d072748 100644 --- a/README.md +++ b/README.md @@ -326,7 +326,8 @@ See also the example [S5ProtoSheet.cs][s5protosheet.cs]. - `Sheet.Scale` - define a scale - `Sheet.ToBook` - make a `Book` with one sheet - `Box` - a box of any type - - `Box.Name` - define a name of the range + - `Box.NameGlobally` - define a book scoped name of the range + - `Box.NameLocally` - define a sheet scoped name of the range - `Box.AutoSpan` - activate `AutoSpan` mode for rows and columns - `Box.AutoSpanRows` - activate `AutoSpan` mode for rows - `Box.AutoSpanCols` - activate `AutoSpan` mode for columns diff --git a/src/BookFx.Tests/BoxTests.cs b/src/BookFx.Tests/BoxTests.cs index ae527be..a363941 100644 --- a/src/BookFx.Tests/BoxTests.cs +++ b/src/BookFx.Tests/BoxTests.cs @@ -20,13 +20,13 @@ public void Implicit_Row_RowBox() } [Property] - public void Name_NonNull_SetName(NonNull name) + public void NameGlobally_NonNull_SetName(NonNull name) { Box box = Make.Row(); - var result = box.Name(name.Get); + var result = box.NameGlobally(name.Get); - result.Get.Name.Should().Be(Some(name.Get)); + result.Get.GlobalName.Should().Be(Some(name.Get)); } } } \ No newline at end of file diff --git a/src/BookFx.Tests/Calculation/MinDimensionCalcTests.cs b/src/BookFx.Tests/Calculation/MinDimensionCalcTests.cs index 58f5cb0..2375d16 100644 --- a/src/BookFx.Tests/Calculation/MinDimensionCalcTests.cs +++ b/src/BookFx.Tests/Calculation/MinDimensionCalcTests.cs @@ -150,7 +150,7 @@ public void MinDimension_ProtoWithoutSlots_AsProto(int protoHeight, int protoWid .Value() .SpanRows(protoHeight) .SpanCols(protoWidth) - .Name(protoRef) + .NameGlobally(protoRef) .ToSheet() .ToBook() .ToBytes(); @@ -168,7 +168,7 @@ public void MinDimension_ProtoWithSlotBox1x1_SlotBox1x1() const string protoRef = "ProtoRef"; var protoBook = Make .Value() - .Name(protoRef) + .NameGlobally(protoRef) .ToSheet() .ToBook() .ToBytes(); diff --git a/src/BookFx.Tests/Calculation/PlacementCalcTests.cs b/src/BookFx.Tests/Calculation/PlacementCalcTests.cs index 2280c0f..b03cfc6 100644 --- a/src/BookFx.Tests/Calculation/PlacementCalcTests.cs +++ b/src/BookFx.Tests/Calculation/PlacementCalcTests.cs @@ -290,8 +290,8 @@ public void Place_ProtoWithSlot_SlotBoxPlaced() var protoBook = Make .Col( "A", - Make.Value("Slot default value").Name(slotRef)) - .Name(protoRef) + Make.Value("Slot default value").NameGlobally(slotRef)) + .NameGlobally(protoRef) .ToSheet() .ToBook() .ToBytes(); diff --git a/src/BookFx.Tests/Calculation/ProtoBankTests.cs b/src/BookFx.Tests/Calculation/ProtoBankTests.cs index 6dbd334..d4739a1 100644 --- a/src/BookFx.Tests/Calculation/ProtoBankTests.cs +++ b/src/BookFx.Tests/Calculation/ProtoBankTests.cs @@ -14,7 +14,7 @@ public void GetRange_NameExists_Expected() { const string theRef = "Ref"; const string theValue = "Value"; - var protoBook = Make.Value(theValue).Name(theRef).ToSheet().ToBook().ToBytes(); + var protoBook = Make.Value(theValue).NameGlobally(theRef).ToSheet().ToBook().ToBytes(); var sut = new ProtoBank(List(protoBook)); var result = sut.GetRange(protoBook, theRef); @@ -37,7 +37,7 @@ public void GetRange_NameNotExists_Invalid() public void GetPosition_NameExists_Expected() { const string theRef = "Ref"; - var protoBook = Make.Value().Name(theRef).ToSheet().ToBook().ToBytes(); + var protoBook = Make.Value().NameGlobally(theRef).ToSheet().ToBook().ToBytes(); var sut = new ProtoBank(List(protoBook)); var result = sut.GetPosition(protoBook, theRef); diff --git a/src/BookFx.Tests/Calculation/ProtoCalcTests.cs b/src/BookFx.Tests/Calculation/ProtoCalcTests.cs index 20cfc5a..1f30353 100644 --- a/src/BookFx.Tests/Calculation/ProtoCalcTests.cs +++ b/src/BookFx.Tests/Calculation/ProtoCalcTests.cs @@ -14,7 +14,7 @@ public void PlugProtos_ProtoBoxWithoutSlots_RangeIsExpected() { const string protoRef = "ProtoRef"; // A - var protoBook = Make.Value().Name(protoRef).ToSheet().ToBook().ToBytes(); + var protoBook = Make.Value().NameGlobally(protoRef).ToSheet().ToBook().ToBytes(); var box = Make.Proto(protoBook, protoRef).Get; var bank = new ProtoBank(List(protoBook)); @@ -37,8 +37,8 @@ public void PlugProtos_ProtoBoxWithSlotAtR2C1_SlotPositionIsR2C1() // A // B var protoBook = Make - .Col("A", Make.Value("B").Name(slotRef)) - .Name(protoRef) + .Col("A", Make.Value("B").NameGlobally(slotRef)) + .NameGlobally(protoRef) .ToSheet() .ToBook() .ToBytes(); diff --git a/src/BookFx.Tests/Renders/BookRenderTests.cs b/src/BookFx.Tests/Renders/BookRenderTests.cs index 38171f1..a40a507 100644 --- a/src/BookFx.Tests/Renders/BookRenderTests.cs +++ b/src/BookFx.Tests/Renders/BookRenderTests.cs @@ -36,7 +36,7 @@ public class BookRenderTests public void Render_ProtoSheet_NameCopiedInBookScope() => Packer.OnPackage(package => Make .Value() - .Name(TheRangeName) + .NameGlobally(TheRangeName) .ToSheet() .ToBook() .ToBytes() @@ -59,7 +59,7 @@ public class BookRenderTests public void Render_ProtoSheetAndNameExists_NameCopiedInSheetScope() => Packer.OnPackage(package => Make .Value() - .Name(TheRangeName) + .NameGlobally(TheRangeName) .ToSheet() .ToBook() .ToBytes() diff --git a/src/BookFx.Tests/Renders/BoxGlobalNameRenderTests.cs b/src/BookFx.Tests/Renders/BoxGlobalNameRenderTests.cs new file mode 100644 index 0000000..5e59224 --- /dev/null +++ b/src/BookFx.Tests/Renders/BoxGlobalNameRenderTests.cs @@ -0,0 +1,53 @@ +namespace BookFx.Tests.Renders +{ + using BookFx.Epplus; + using BookFx.Renders; + using FluentAssertions; + using FsCheck.Xunit; + using Xunit; + + [Properties(MaxTest = 10)] + public class BoxGlobalNameRenderTests + { + private const string TheValidName = "TheName"; + + [Fact] + public void GlobalNameRender_NoName_NotSet() => + Packer.OnSheet(excelSheet => + { + var excelRange = excelSheet.Cells[1, 1]; + + Make.Value().Get.GlobalNameRender()(excelRange); + + excelRange.Worksheet.Workbook.Names.Should().BeEmpty(); + }); + + [Fact] + public void GlobalNameRender_NonEmptyName_Set() => + Packer.OnSheet(excelSheet => + { + var box = Make.Value().NameGlobally(TheValidName).Get; + var excelRange = excelSheet.Cells[1, 1]; + + box.GlobalNameRender()(excelRange); + + excelRange.Worksheet.Workbook.Names + .Should() + .HaveCount(1) + .And.OnlyContain(x => x.Name == TheValidName && x.Address == excelRange.Address); + }); + + [Fact] + public void GlobalNameRender_NameIsAlreadyExists_Error() => + Packer.OnSheet(excelSheet => + { + excelSheet.Workbook.Names.Add(TheValidName, excelSheet.Cells[2, 2]); + var box = Make.Value().NameGlobally(TheValidName).Get; + var excelRange = excelSheet.Cells[1, 1]; + + var result = box.GlobalNameRender()(excelRange); + + result.IsValid.Should().BeFalse(); + }); + } +} \ No newline at end of file diff --git a/src/BookFx.Tests/Renders/BoxLocalNameRenderTests.cs b/src/BookFx.Tests/Renders/BoxLocalNameRenderTests.cs new file mode 100644 index 0000000..fd398b7 --- /dev/null +++ b/src/BookFx.Tests/Renders/BoxLocalNameRenderTests.cs @@ -0,0 +1,53 @@ +namespace BookFx.Tests.Renders +{ + using BookFx.Epplus; + using BookFx.Renders; + using FluentAssertions; + using FsCheck.Xunit; + using Xunit; + + [Properties(MaxTest = 10)] + public class BoxLocalNameRenderTests + { + private const string TheValidName = "TheName"; + + [Fact] + public void LocalNameRender_NoName_NotSet() => + Packer.OnSheet(excelSheet => + { + var excelRange = excelSheet.Cells[1, 1]; + + Make.Value().Get.LocalNameRender()(excelRange); + + excelRange.Worksheet.Names.Should().BeEmpty(); + }); + + [Fact] + public void LocalNameRender_NonEmptyName_Set() => + Packer.OnSheet(excelSheet => + { + var box = Make.Value().NameLocally(TheValidName).Get; + var excelRange = excelSheet.Cells[1, 1]; + + box.LocalNameRender()(excelRange); + + excelRange.Worksheet.Names + .Should() + .HaveCount(1) + .And.OnlyContain(x => x.Name == TheValidName && x.Address == excelRange.Address); + }); + + [Fact] + public void LocalNameRender_NameIsAlreadyExists_Error() => + Packer.OnSheet(excelSheet => + { + excelSheet.Names.Add(TheValidName, excelSheet.Cells[2, 2]); + var box = Make.Value().NameLocally(TheValidName).Get; + var excelRange = excelSheet.Cells[1, 1]; + + var result = box.LocalNameRender()(excelRange); + + result.IsValid.Should().BeFalse(); + }); + } +} \ No newline at end of file diff --git a/src/BookFx.Tests/Renders/BoxNameRenderTests.cs b/src/BookFx.Tests/Renders/BoxNameRenderTests.cs deleted file mode 100644 index a0376cc..0000000 --- a/src/BookFx.Tests/Renders/BoxNameRenderTests.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace BookFx.Tests.Renders -{ - using System; - using BookFx.Cores; - using BookFx.Epplus; - using BookFx.Renders; - using FluentAssertions; - using FsCheck.Xunit; - using OfficeOpenXml; - using Xunit; - - [Properties(MaxTest = 10)] - public class BoxNameRenderTests - { - private const string TheValidName = "TheName"; - - [Fact] - public void NameRender_NoName_NotSet() => - Check( - Make.Value().Get, - range => range.Worksheet.Workbook.Names.Should().BeEmpty()); - - [Fact] - public void NameRender_NonEmptyName_Set() => - Check( - Make.Value().Name(TheValidName).Get, - range => range.Worksheet.Workbook.Names - .Should() - .HaveCount(1) - .And.OnlyContain(x => x.Name == TheValidName && x.Address == range.Address)); - - [Fact] - public void NameRender_NameIsAlreadyExists_Error() => - Packer.OnSheet(excelSheet => - { - excelSheet.Workbook.Names.Add(TheValidName, excelSheet.Cells[2, 2]); - var box = Make.Value().Name(TheValidName).Get; - var excelRange = excelSheet.Cells[1, 1]; - - var result = box.NameRender()(excelRange); - - result.IsValid.Should().BeFalse(); - }); - - private static void Check(BoxCore box, Action assertion) => - Packer.OnSheet(excelSheet => - { - var excelRange = excelSheet.Cells[1, 1]; - - box.NameRender()(excelRange); - - assertion(excelRange); - }); - } -} \ No newline at end of file diff --git a/src/BookFx.Tests/Validation/BookValidatorTests.cs b/src/BookFx.Tests/Validation/BookValidatorTests.cs index ab75191..c4020da 100644 --- a/src/BookFx.Tests/Validation/BookValidatorTests.cs +++ b/src/BookFx.Tests/Validation/BookValidatorTests.cs @@ -38,29 +38,29 @@ public void SheetNameUniqueness_NonUniqueSheetNames_Invalid() } [Fact] - public void BoxNameUniqueness_UniqueBoxNames_Valid() + public void BoxGlobalNameUniqueness_UniqueBoxNames_Valid() { var book = Make .Book( - Make.Sheet(Make.Row(Make.Value().Name("AA"), Make.Value().Name("AB"))), - Make.Sheet(Make.Row(Make.Value().Name("BA"), Make.Value().Name("BB")))) + Make.Sheet(Make.Row(Make.Value().NameGlobally("AA"), Make.Value().NameGlobally("AB"))), + Make.Sheet(Make.Row(Make.Value().NameGlobally("BA"), Make.Value().NameGlobally("BB")))) .Get; - var result = BookValidator.BoxNameUniqueness(book); + var result = BookValidator.BoxGlobalNameUniqueness(book); result.IsValid.Should().BeTrue(); } [Fact] - public void BoxNameUniqueness_NonUniqueBoxNames_Invalid() + public void BoxGlobalNameUniqueness_NonUniqueBoxNames_Invalid() { var book = Make .Book( - Make.Sheet(Make.Value().Name("A")), - Make.Sheet(Make.Value().Name("A"))) + Make.Sheet(Make.Value().NameGlobally("A")), + Make.Sheet(Make.Value().NameGlobally("A"))) .Get; - var result = BookValidator.BoxNameUniqueness(book); + var result = BookValidator.BoxGlobalNameUniqueness(book); result.IsValid.Should().BeFalse(); } diff --git a/src/BookFx.Tests/Validation/BoxValidatorTests.cs b/src/BookFx.Tests/Validation/BoxValidatorTests.cs index 71d8f75..a56300d 100644 --- a/src/BookFx.Tests/Validation/BoxValidatorTests.cs +++ b/src/BookFx.Tests/Validation/BoxValidatorTests.cs @@ -190,9 +190,9 @@ public void ColSizeRange_InvalidSizes_Invalid(double size) [InlineData("年")] public void Name_ValidName_ValidResult(string rangeName) { - var box = Make.Value().Name(rangeName).Get; + var box = Make.Value().NameGlobally(rangeName).Get; - var result = BoxValidator.Name(box); + var result = BoxValidator.Name(x => x.GlobalName)(box); result.IsValid.Should().BeTrue(); } @@ -201,6 +201,8 @@ public void Name_ValidName_ValidResult(string rangeName) [InlineData("")] [InlineData("1")] [InlineData("123")] + [InlineData("1year")] + [InlineData("1год")] [InlineData("A1")] [InlineData("R1C1")] [InlineData("rc")] @@ -215,9 +217,9 @@ public void Name_ValidName_ValidResult(string rangeName) [InlineData("=")] public void Name_InvalidName_InvalidResult(string rangeName) { - var box = Make.Value().Name(rangeName).Get; + var box = Make.Value().NameGlobally(rangeName).Get; - var result = BoxValidator.Name(box); + var result = BoxValidator.Name(x => x.GlobalName)(box); result.IsValid.Should().BeFalse(); } diff --git a/src/BookFx.Tests/Validation/SheetValidatorTests.cs b/src/BookFx.Tests/Validation/SheetValidatorTests.cs index df82246..7e13777 100644 --- a/src/BookFx.Tests/Validation/SheetValidatorTests.cs +++ b/src/BookFx.Tests/Validation/SheetValidatorTests.cs @@ -40,6 +40,26 @@ public void SheetName_InvalidNames_Invalid(string name) SheetValidator.SheetName(sheet).IsValid.Should().BeFalse(); } + [Fact] + public void BoxLocalNameUniqueness_UniqueBoxNames_Valid() + { + var sheet = Make.Sheet(Make.Row(Make.Value().NameLocally("A"), Make.Value().NameLocally("B"))).Get; + + var result = SheetValidator.BoxLocalNameUniqueness(sheet); + + result.IsValid.Should().BeTrue(); + } + + [Fact] + public void BoxLocalNameUniqueness_NonUniqueBoxNames_Invalid() + { + var sheet = Make.Sheet(Make.Row(Make.Value().NameLocally("A"), Make.Value().NameLocally("A"))).Get; + + var result = SheetValidator.BoxLocalNameUniqueness(sheet); + + result.IsValid.Should().BeFalse(); + } + [Fact] public void Margins_Empty_Valid() { diff --git a/src/BookFx.Tests/ValueBoxTests.cs b/src/BookFx.Tests/ValueBoxTests.cs index 1cef2a0..d63305d 100644 --- a/src/BookFx.Tests/ValueBoxTests.cs +++ b/src/BookFx.Tests/ValueBoxTests.cs @@ -25,7 +25,7 @@ public class ValueBoxTests Make.Value(Unit()).Get.Content.ValueUnsafe().Should().BeOfType(); [Property] - public void Name_NonNull_NameIsName(NonNull name) => - Make.Value().Name(name.Get).Get.Name.ValueUnsafe().Should().Be(name.Get); + public void NameGlobally_NonNull_GlobalNameIsName(NonNull name) => + Make.Value().NameGlobally(name.Get).Get.GlobalName.ValueUnsafe().Should().Be(name.Get); } } \ No newline at end of file diff --git a/src/BookFx.Usage/S1Table.cs b/src/BookFx.Usage/S1Table.cs index 7bb51da..541ba88 100644 --- a/src/BookFx.Usage/S1Table.cs +++ b/src/BookFx.Usage/S1Table.cs @@ -13,7 +13,7 @@ public static class S1Table .Add(Col() .Add(Data("00001", "First long name with auto fit", 1000, 1020, 1500, 1550)) .Add(Data("00002", "Second long name with auto fit", 1200, 1240, 1600, 1690)) - .Name("Data")) + .NameGlobally("Data")) .Add(Total()) .AutoSpan() .Style(Style().DefaultBorder()) diff --git a/src/BookFx.Usage/S2Style.cs b/src/BookFx.Usage/S2Style.cs index 6f6d719..51e6313 100644 --- a/src/BookFx.Usage/S2Style.cs +++ b/src/BookFx.Usage/S2Style.cs @@ -5,9 +5,9 @@ public static class S2Style { - public static string PrototypeName => "ThePrototype"; + public static string PrototypeName => "ThePrototype"; // will be used in S6ProtoBox - public static string SlotName => "TheSlot"; + public static string SlotName => "TheSlot"; // will be used in S6ProtoBox public static byte[] Create() => Col() @@ -30,11 +30,11 @@ public static class S2Style ) .Add(Row() .Add(Value("Red", Style().Font(Color.Red))) - .Add(Value("On green", Style().Back(Color.LightGreen)).Name(SlotName)) // will be used in S6ProtoBox + .Add(Value("On green", Style().Back(Color.LightGreen)).NameGlobally(SlotName)) .Add(Value("Arial 12", Style().Font("Arial", 12))) .Add(Value("Wrapped long text", Style().Wrap())) ) - .Name(PrototypeName) // will be used in S6ProtoBox + .NameGlobally(PrototypeName) .ToSheet() .ToBook() .ToBytes(); diff --git a/src/BookFx/Box.cs b/src/BookFx/Box.cs index 572b45c..5ed4664 100644 --- a/src/BookFx/Box.cs +++ b/src/BookFx/Box.cs @@ -100,11 +100,23 @@ public class Box public static implicit operator Box(Guid content) => Value(content); /// - /// Define a name of the range. + /// Define a book scoped name of the range. /// /// A range name. [Pure] - public Box Name(string rangeName) => Get.With(name: Some(rangeName)); + public Box NameGlobally(string rangeName) => Get.With(globalName: Some(rangeName)); + + /// + /// Define a sheet scoped name of the range. + /// + /// A range name. + [Pure] + public Box NameLocally(string rangeName) => Get.With(localName: Some(rangeName)); + + /// + [Obsolete("Use NameGlobally or NameLocally instead.")] + [Pure] + public Box Name(string rangeName) => NameGlobally(rangeName); /// /// Enables automatic span when a box can be stretched to its contrainer. diff --git a/src/BookFx/ColBox.cs b/src/BookFx/ColBox.cs index b528beb..9cd52ed 100644 --- a/src/BookFx/ColBox.cs +++ b/src/BookFx/ColBox.cs @@ -1,5 +1,6 @@ namespace BookFx { + using System; using System.Collections.Generic; using System.Linq; using BookFx.Cores; @@ -29,9 +30,18 @@ private ColBox(BoxCore core) [Pure] public static implicit operator ColBox(BoxCore core) => new ColBox(core); + /// + [Pure] + public new ColBox NameGlobally(string rangeName) => Get.With(globalName: Some(rangeName)); + + /// + [Pure] + public new ColBox NameLocally(string rangeName) => Get.With(localName: Some(rangeName)); + /// + [Obsolete("Use NameGlobally or NameLocally instead.")] [Pure] - public new ColBox Name(string rangeName) => Get.With(name: Some(rangeName)); + public new ColBox Name(string rangeName) => NameGlobally(rangeName); /// [Pure] diff --git a/src/BookFx/Cores/BoxCore.cs b/src/BookFx/Cores/BoxCore.cs index cd84ffb..151e977 100644 --- a/src/BookFx/Cores/BoxCore.cs +++ b/src/BookFx/Cores/BoxCore.cs @@ -1,5 +1,6 @@ namespace BookFx.Cores { + using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -17,7 +18,8 @@ public sealed class BoxCore private BoxCore( BoxType type, - Option name, + Option globalName, + Option localName, Option style, IEnumerable rowSizes, IEnumerable colSizes, @@ -40,7 +42,8 @@ public sealed class BoxCore Placement placement) { Type = type; - Name = name; + GlobalName = globalName; + LocalName = localName; Style = style; IsPrintArea = isPrintArea; AreRowsHidden = areRowsHidden; @@ -69,9 +72,18 @@ public sealed class BoxCore public BoxType Type { get; } /// - /// Gets the range name. + /// Gets the book scoped range name. /// - public Option Name { get; } + public Option GlobalName { get; } + + /// + /// Gets the sheet scoped range name. + /// + public Option LocalName { get; } + + /// + [Obsolete("Use GlobalName or LocalName instead.")] + public Option Name => GlobalName; /// /// Gets the style. @@ -174,7 +186,8 @@ public sealed class BoxCore Option? style = null) => new BoxCore( type: type, - name: None, + globalName: None, + localName: None, style: style ?? None, rowSizes: Enumerable.Empty(), colSizes: Enumerable.Empty(), @@ -207,7 +220,8 @@ public sealed class BoxCore [Pure] internal BoxCore With( BoxType? type = null, - Option? name = null, + Option? globalName = null, + Option? localName = null, Option? style = null, IEnumerable? rowSizes = null, IEnumerable? colSizes = null, @@ -230,7 +244,8 @@ public sealed class BoxCore Placement? placement = null) => new BoxCore( type ?? Type, - name ?? Name, + globalName ?? GlobalName, + localName ?? LocalName, style ?? Style, rowSizes ?? RowSizes, colSizes ?? ColSizes, diff --git a/src/BookFx/Errors.cs b/src/BookFx/Errors.cs index 5484710..8256d4d 100644 --- a/src/BookFx/Errors.cs +++ b/src/BookFx/Errors.cs @@ -16,8 +16,8 @@ public static class Book new SheetNameIsNotUniqueError(name); [Pure] - public static BoxNameIsNotUniqueError BoxNameIsNotUnique(string name) => - new BoxNameIsNotUniqueError(name); + public static BoxGlobalNameIsNotUniqueError BoxGlobalNameIsNotUnique(string name) => + new BoxGlobalNameIsNotUniqueError(name); [Pure] public static AggregateError Aggregate(IEnumerable inners) => @@ -31,10 +31,10 @@ public SheetNameIsNotUniqueError(string name) } } - public sealed class BoxNameIsNotUniqueError : Error + public sealed class BoxGlobalNameIsNotUniqueError : Error { - public BoxNameIsNotUniqueError(string name) - : base($"Box name «{name}» is not unique.") + public BoxGlobalNameIsNotUniqueError(string name) + : base($"Book scoped name «{name}» of box is not unique.") { } } @@ -53,6 +53,9 @@ public static class Sheet [Pure] public static NameIsInvalidError NameIsInvalid(string name) => new NameIsInvalidError(name); + [Pure] + public static BoxLocalNameIsNotUniqueError BoxLocalNameIsNotUnique(string name) => new(name); + [Pure] public static ManyPrintAreasError ManyPrintAreas() => new ManyPrintAreasError(); @@ -98,6 +101,14 @@ public NameIsInvalidError(string name) } } + public sealed class BoxLocalNameIsNotUniqueError : Error + { + public BoxLocalNameIsNotUniqueError(string name) + : base($"Sheet scoped name «{name}» of box is not unique.") + { + } + } + public sealed class ManyPrintAreasError : Error { public ManyPrintAreasError() @@ -294,10 +305,13 @@ public sealed class AggregateError : Error { public AggregateError(BoxCore box, IEnumerable inners) : base( - $"{box.Name.Map(name => $"Box «{name}»").GetOrElse("Unnamed box")} has following errors.", + $"{BoxName(box)} has following errors.", inners) { } + + private static string BoxName(BoxCore box) => + box.LocalName.OrElse(box.GlobalName).Map(name => $"Box «{name}»").GetOrElse("Unnamed box"); } } diff --git a/src/BookFx/ProtoBox.cs b/src/BookFx/ProtoBox.cs index 789c74b..2a8f1d9 100644 --- a/src/BookFx/ProtoBox.cs +++ b/src/BookFx/ProtoBox.cs @@ -1,5 +1,6 @@ namespace BookFx { + using System; using System.Collections.Generic; using System.Linq; using BookFx.Cores; @@ -55,9 +56,18 @@ private ProtoBox(BoxCore core) [Pure] public new ProtoBox AutoSpanCols(bool isEnabled) => Get.With(colAutoSpan: isEnabled); + /// + [Pure] + public new ProtoBox NameGlobally(string rangeName) => Get.With(globalName: Some(rangeName)); + + /// + [Pure] + public new ProtoBox NameLocally(string rangeName) => Get.With(localName: Some(rangeName)); + /// + [Obsolete("Use NameGlobally or NameLocally instead.")] [Pure] - public new ProtoBox Name(string rangeName) => Get.With(name: Some(rangeName)); + public new ProtoBox Name(string rangeName) => NameGlobally(rangeName); /// [Pure] diff --git a/src/BookFx/Renders/BoxNameRender.cs b/src/BookFx/Renders/BoxGlobalNameRender.cs similarity index 67% rename from src/BookFx/Renders/BoxNameRender.cs rename to src/BookFx/Renders/BoxGlobalNameRender.cs index 560b9c6..75d248f 100644 --- a/src/BookFx/Renders/BoxNameRender.cs +++ b/src/BookFx/Renders/BoxGlobalNameRender.cs @@ -5,16 +5,16 @@ using OfficeOpenXml; using static BookFx.Functional.F; - internal static class BoxNameRender + internal static class BoxGlobalNameRender { - public static Tee NameRender(this BoxCore box) => - excelRange => box.Name.Match( + public static Tee GlobalNameRender(this BoxCore box) => + excelRange => box.GlobalName.Match( none: () => Valid(Unit()), some: name => { if (excelRange.Worksheet.Workbook.Names.ContainsKey(name)) { - return Errors.Book.BoxNameIsNotUnique(name); + return Errors.Book.BoxGlobalNameIsNotUnique(name); } excelRange.Worksheet.Workbook.Names.Add(name, excelRange); diff --git a/src/BookFx/Renders/BoxLocalNameRender.cs b/src/BookFx/Renders/BoxLocalNameRender.cs new file mode 100644 index 0000000..f156aa7 --- /dev/null +++ b/src/BookFx/Renders/BoxLocalNameRender.cs @@ -0,0 +1,24 @@ +namespace BookFx.Renders +{ + using BookFx.Cores; + using BookFx.Functional; + using OfficeOpenXml; + + internal static class BoxLocalNameRender + { + public static Tee LocalNameRender(this BoxCore box) => + excelRange => box.LocalName.Match( + none: () => F.Valid(F.Unit()), + some: name => + { + if (excelRange.Worksheet.Names.ContainsKey(name)) + { + return Errors.Sheet.BoxLocalNameIsNotUnique(name); + } + + excelRange.Worksheet.Names.Add(name, excelRange); + + return F.Valid(F.Unit()); + }); + } +} \ No newline at end of file diff --git a/src/BookFx/Renders/BoxRender.cs b/src/BookFx/Renders/BoxRender.cs index a6c6c99..26bd600 100644 --- a/src/BookFx/Renders/BoxRender.cs +++ b/src/BookFx/Renders/BoxRender.cs @@ -13,7 +13,8 @@ internal static class BoxRender box.MergeRender(), box.StyleRender(), box.DescendantsRender(), - box.NameRender(), + box.GlobalNameRender(), + box.LocalNameRender(), box.ContentRender(), box.AutoFilterRender(), box.PrintAreaRender()); diff --git a/src/BookFx/RowBox.cs b/src/BookFx/RowBox.cs index 2cb47c8..b1c8236 100644 --- a/src/BookFx/RowBox.cs +++ b/src/BookFx/RowBox.cs @@ -1,5 +1,6 @@ namespace BookFx { + using System; using System.Collections.Generic; using System.Linq; using BookFx.Cores; @@ -29,9 +30,18 @@ private RowBox(BoxCore core) [Pure] public static implicit operator RowBox(BoxCore core) => new RowBox(core); + /// + [Pure] + public new RowBox NameGlobally(string rangeName) => Get.With(globalName: Some(rangeName)); + + /// + [Pure] + public new RowBox NameLocally(string rangeName) => Get.With(localName: Some(rangeName)); + /// + [Obsolete("Use NameGlobally or NameLocally instead.")] [Pure] - public new RowBox Name(string rangeName) => Get.With(name: Some(rangeName)); + public new RowBox Name(string rangeName) => NameGlobally(rangeName); /// [Pure] diff --git a/src/BookFx/StackBox.cs b/src/BookFx/StackBox.cs index b08afce..59ef2cf 100644 --- a/src/BookFx/StackBox.cs +++ b/src/BookFx/StackBox.cs @@ -1,5 +1,6 @@ namespace BookFx { + using System; using System.Collections.Generic; using System.Linq; using BookFx.Cores; @@ -29,9 +30,18 @@ private StackBox(BoxCore core) [Pure] public static implicit operator StackBox(BoxCore core) => new StackBox(core); + /// + [Pure] + public new StackBox NameGlobally(string rangeName) => Get.With(globalName: Some(rangeName)); + + /// + [Pure] + public new StackBox NameLocally(string rangeName) => Get.With(localName: Some(rangeName)); + /// + [Obsolete("Use NameGlobally or NameLocally instead.")] [Pure] - public new StackBox Name(string rangeName) => Get.With(name: Some(rangeName)); + public new StackBox Name(string rangeName) => NameGlobally(rangeName); /// [Pure] diff --git a/src/BookFx/Validation/BookValidator.cs b/src/BookFx/Validation/BookValidator.cs index 7ce93aa..5e56dec 100644 --- a/src/BookFx/Validation/BookValidator.cs +++ b/src/BookFx/Validation/BookValidator.cs @@ -10,7 +10,7 @@ internal static class BookValidator public static Validator Validate => HarvestErrors( SheetNameUniqueness, - BoxNameUniqueness, + BoxGlobalNameUniqueness, Sheets); public static Validator SheetNameUniqueness => @@ -20,13 +20,13 @@ internal static class BookValidator .Traverse(name => Invalid(Errors.Book.SheetNameIsNotUnique(name))) .Map(_ => book); - public static Validator BoxNameUniqueness => + public static Validator BoxGlobalNameUniqueness => book => book.Sheets .Bind(x => x.Box) .Bind(x => x.SelfAndDescendants()) - .Bind(x => x.Name) + .Bind(x => x.GlobalName) .NonUnique() - .Traverse(name => Invalid(Errors.Book.BoxNameIsNotUnique(name))) + .Traverse(name => Invalid(Errors.Book.BoxGlobalNameIsNotUnique(name))) .Map(_ => book); public static Validator Sheets => diff --git a/src/BookFx/Validation/BoxValidator.cs b/src/BookFx/Validation/BoxValidator.cs index 805e1b6..4335a15 100644 --- a/src/BookFx/Validation/BoxValidator.cs +++ b/src/BookFx/Validation/BoxValidator.cs @@ -1,5 +1,6 @@ namespace BookFx.Validation { + using System; using System.Linq; using BookFx.Cores; using BookFx.Epplus; @@ -15,7 +16,8 @@ internal static class BoxValidator ColSpanSize, RowSizeRange, ColSizeRange, - Name, + Name(box => box.GlobalName), + Name(box => box.LocalName), Style); public static Validator RowSpanSize => @@ -48,16 +50,6 @@ internal static class BoxValidator one: size => Errors.Box.ColSizesAreInvalid(size), more: (size, others) => Errors.Box.ColSizesAreInvalid(size, others)); - public static Validator Name => - box => box.Name.Match( - none: () => Valid(box), - some: name => - Constraint.RangeNameRegex.IsMatch(name) && - !Constraint.A1RangeNameRegex.IsMatch(name) && - !Constraint.R1C1RangeNameRegex.IsMatch(name) - ? Valid(box) - : Errors.Box.NameIsInvalid(name)); - public static Validator Style => box => box.Style .Map(StyleValidator.Validate.Invoke) @@ -66,5 +58,15 @@ internal static class BoxValidator some: result => result.Match( invalid: errors => Errors.Box.Aggregate(box, errors), valid: _ => Valid(box))); + + public static Validator Name(Func> getName) => + box => getName(box).Match( + none: () => Valid(box), + some: name => + Constraint.RangeNameRegex.IsMatch(name) && + !Constraint.A1RangeNameRegex.IsMatch(name) && + !Constraint.R1C1RangeNameRegex.IsMatch(name) + ? Valid(box) + : Errors.Box.NameIsInvalid(name)); } } \ No newline at end of file diff --git a/src/BookFx/Validation/SheetValidator.cs b/src/BookFx/Validation/SheetValidator.cs index 1f305b4..07bf5b3 100644 --- a/src/BookFx/Validation/SheetValidator.cs +++ b/src/BookFx/Validation/SheetValidator.cs @@ -12,6 +12,7 @@ internal static class SheetValidator public static Validator Validate => HarvestErrors( SheetName, + BoxLocalNameUniqueness, PrintArea, Margins, FitToHeight, @@ -28,6 +29,16 @@ internal static class SheetValidator .Map(name => Invalid(Errors.Sheet.NameIsInvalid(name))) .GetOrElse(Valid(sheet)); + public static Validator BoxLocalNameUniqueness => + sheet => sheet + .Box + .AsEnumerable() + .Bind(x => x.SelfAndDescendants()) + .Bind(x => x.LocalName) + .NonUnique() + .Traverse(name => Invalid(Errors.Sheet.BoxLocalNameIsNotUnique(name))) + .Map(_ => sheet); + public static Validator PrintArea => sheet => sheet .Box diff --git a/src/BookFx/ValueBox.cs b/src/BookFx/ValueBox.cs index 9082741..93e523f 100644 --- a/src/BookFx/ValueBox.cs +++ b/src/BookFx/ValueBox.cs @@ -96,9 +96,18 @@ private ValueBox(BoxCore core) [Pure] public static implicit operator ValueBox(Guid content) => Value(content); + /// + [Pure] + public new ValueBox NameGlobally(string rangeName) => Get.With(globalName: Some(rangeName)); + + /// + [Pure] + public new ValueBox NameLocally(string rangeName) => Get.With(localName: Some(rangeName)); + /// + [Obsolete("Use NameGlobally or NameLocally instead.")] [Pure] - public new ValueBox Name(string rangeName) => Get.With(name: Some(rangeName)); + public new ValueBox Name(string rangeName) => NameGlobally(rangeName); /// [Pure] From 19afc92aa32c629993a21804c1f96ca3b46a2000 Mon Sep 17 00:00:00 2001 From: Zhenya Gusev <45536778+zhenyagusev@users.noreply.github.com> Date: Fri, 11 Feb 2022 10:42:27 +0300 Subject: [PATCH 2/2] use NameLocally in S1Table --- src/BookFx.Usage/S1Table.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BookFx.Usage/S1Table.cs b/src/BookFx.Usage/S1Table.cs index 541ba88..e3aee65 100644 --- a/src/BookFx.Usage/S1Table.cs +++ b/src/BookFx.Usage/S1Table.cs @@ -13,7 +13,7 @@ public static class S1Table .Add(Col() .Add(Data("00001", "First long name with auto fit", 1000, 1020, 1500, 1550)) .Add(Data("00002", "Second long name with auto fit", 1200, 1240, 1600, 1690)) - .NameGlobally("Data")) + .NameLocally("Data")) .Add(Total()) .AutoSpan() .Style(Style().DefaultBorder())